From 2e867a946f903b33de7c8b8eb80c8a271b6511d0 Mon Sep 17 00:00:00 2001 From: miruku Date: Wed, 21 Jan 2026 13:46:12 +0800 Subject: [PATCH] fix: dconfig2cpp: ensure isInitializeSucceeded() is true only after all config entries has been updated. Change: - queue `m_status` change in the main thread, after all queued config init invocations, to ensure thread safety. - updated generated headers in project. --- src/log/dconfig_org_deepin_dtk_preference.hpp | 29 ++++++++++--------- .../dconfig2cpp/dconf-example_meta.hpp | 29 ++++++++++--------- ...dconf-example_other_app_configure_meta.hpp | 29 ++++++++++--------- .../dconfig2cpp/dconf-global_meta.hpp | 29 ++++++++++--------- tools/dconfig2cpp/main.cpp | 27 ++++++++--------- 5 files changed, 74 insertions(+), 69 deletions(-) diff --git a/src/log/dconfig_org_deepin_dtk_preference.hpp b/src/log/dconfig_org_deepin_dtk_preference.hpp index 9907a7c5..5a318c8a 100644 --- a/src/log/dconfig_org_deepin_dtk_preference.hpp +++ b/src/log/dconfig_org_deepin_dtk_preference.hpp @@ -1,7 +1,7 @@ /** * This file is generated by dconfig2cpp. * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp /usr/share/dsg/configs/org.deepin.dtk.preference.json -o ./src/log/dconfig_org_deepin_dtk_preference.hpp - * Generation time: 2026-01-20T14:15:13 + * Generation time: 2026-01-21T14:01:24 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. @@ -119,22 +119,23 @@ class dconfig_org_deepin_dtk_preference : public QObject { // Initialize through Data class safeData->initializeInConfigThread(config); - // Try to transition from Initializing to Succeeded - if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), - static_cast(Data::Status::Succeeded))) { - // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread - QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); - QMetaObject::invokeMethod(safeData, [safeData, config]() { + QMetaObject::invokeMethod(safeData, [safeData, config]() { + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread + QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); if (safeData->m_userConfig) { Q_EMIT safeData->m_userConfig->configInitializeSucceed(config); } - }, Qt::QueuedConnection); - } else { - // CAS failed - state changed (e.g., set to Destroyed) - // We must clean up the config we just created - config->deleteLater(); - safeData->deleteLater(); - } + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); + } + }, Qt::QueuedConnection); + }); } static dconfig_org_deepin_dtk_preference* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) diff --git a/toolGenerate/dconfig2cpp/dconf-example_meta.hpp b/toolGenerate/dconfig2cpp/dconf-example_meta.hpp index e0a29e0a..ec641497 100644 --- a/toolGenerate/dconfig2cpp/dconf-example_meta.hpp +++ b/toolGenerate/dconfig2cpp/dconf-example_meta.hpp @@ -1,7 +1,7 @@ /** * This file is generated by dconfig2cpp. * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp ./tests/data/dconf-example.meta.json -o ./toolGenerate/dconfig2cpp/dconf-example_meta.hpp - * Generation time: 2026-01-20T14:15:13 + * Generation time: 2026-01-21T14:02:08 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. @@ -121,22 +121,23 @@ class dconfig_dconf-example_meta : public QObject { // Initialize through Data class safeData->initializeInConfigThread(config); - // Try to transition from Initializing to Succeeded - if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), - static_cast(Data::Status::Succeeded))) { - // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread - QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); - QMetaObject::invokeMethod(safeData, [safeData, config]() { + QMetaObject::invokeMethod(safeData, [safeData, config]() { + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread + QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); if (safeData->m_userConfig) { Q_EMIT safeData->m_userConfig->configInitializeSucceed(config); } - }, Qt::QueuedConnection); - } else { - // CAS failed - state changed (e.g., set to Destroyed) - // We must clean up the config we just created - config->deleteLater(); - safeData->deleteLater(); - } + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); + } + }, Qt::QueuedConnection); + }); } static dconfig_dconf-example_meta* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) diff --git a/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp b/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp index 72e9298a..008143a4 100644 --- a/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp +++ b/toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp @@ -1,7 +1,7 @@ /** * This file is generated by dconfig2cpp. * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp ./tests/data/dconf-example_other_app_configure.meta.json -o ./toolGenerate/dconfig2cpp/dconf-example_other_app_configure_meta.hpp - * Generation time: 2026-01-20T14:15:13 + * Generation time: 2026-01-21T14:02:20 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. @@ -109,22 +109,23 @@ class dconfig_dconf-example_other_app_configure_meta : public QObject { // Initialize through Data class safeData->initializeInConfigThread(config); - // Try to transition from Initializing to Succeeded - if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), - static_cast(Data::Status::Succeeded))) { - // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread - QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); - QMetaObject::invokeMethod(safeData, [safeData, config]() { + QMetaObject::invokeMethod(safeData, [safeData, config]() { + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread + QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); if (safeData->m_userConfig) { Q_EMIT safeData->m_userConfig->configInitializeSucceed(config); } - }, Qt::QueuedConnection); - } else { - // CAS failed - state changed (e.g., set to Destroyed) - // We must clean up the config we just created - config->deleteLater(); - safeData->deleteLater(); - } + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); + } + }, Qt::QueuedConnection); + }); } static dconfig_dconf-example_other_app_configure_meta* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) diff --git a/toolGenerate/dconfig2cpp/dconf-global_meta.hpp b/toolGenerate/dconfig2cpp/dconf-global_meta.hpp index 576ffc49..9854503e 100644 --- a/toolGenerate/dconfig2cpp/dconf-global_meta.hpp +++ b/toolGenerate/dconfig2cpp/dconf-global_meta.hpp @@ -1,7 +1,7 @@ /** * This file is generated by dconfig2cpp. * Command line arguments: ./build/tools/dconfig2cpp/dconfig2cpp ./tests/data/dconf-global.meta.json -o ./toolGenerate/dconfig2cpp/dconf-global_meta.hpp - * Generation time: 2026-01-20T14:15:13 + * Generation time: 2026-01-21T14:02:35 * JSON file version: 1.0 * * WARNING: DO NOT MODIFY THIS FILE MANUALLY. @@ -108,22 +108,23 @@ class dconfig_dconf-global_meta : public QObject { // Initialize through Data class safeData->initializeInConfigThread(config); - // Try to transition from Initializing to Succeeded - if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), - static_cast(Data::Status::Succeeded))) { - // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread - QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); - QMetaObject::invokeMethod(safeData, [safeData, config]() { + QMetaObject::invokeMethod(safeData, [safeData, config]() { + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread + QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); if (safeData->m_userConfig) { Q_EMIT safeData->m_userConfig->configInitializeSucceed(config); } - }, Qt::QueuedConnection); - } else { - // CAS failed - state changed (e.g., set to Destroyed) - // We must clean up the config we just created - config->deleteLater(); - safeData->deleteLater(); - } + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); + } + }, Qt::QueuedConnection); + }); } static dconfig_dconf-global_meta* create(const QString &appId = {}, const QString &subpath = {}, QObject *parent = nullptr, QThread *thread = DTK_CORE_NAMESPACE::DConfig::globalThread()) diff --git a/tools/dconfig2cpp/main.cpp b/tools/dconfig2cpp/main.cpp index 8b655f59..4c1804b1 100644 --- a/tools/dconfig2cpp/main.cpp +++ b/tools/dconfig2cpp/main.cpp @@ -355,22 +355,23 @@ int main(int argc, char *argv[]) { // Initialize through Data class safeData->initializeInConfigThread(config); - // Try to transition from Initializing to Succeeded - if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), - static_cast(Data::Status::Succeeded))) { - // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread - QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); - QMetaObject::invokeMethod(safeData, [safeData, config]() { + // Queue state transition to main thread, to ensure config values are fully initialized. + QMetaObject::invokeMethod(safeData, [safeData, config]() { + // Try to transition from Initializing to Succeeded + if (safeData->m_status.testAndSetOrdered(static_cast(Data::Status::Initializing), + static_cast(Data::Status::Succeeded))) { + // CAS succeeded: connect config destroyed signal to cleanup Data, then emit success signal to main thread + QObject::connect(config, &QObject::destroyed, safeData, &QObject::deleteLater); if (safeData->m_userConfig) { Q_EMIT safeData->m_userConfig->configInitializeSucceed(config); } - }, Qt::QueuedConnection); - } else { - // CAS failed - state changed (e.g., set to Destroyed) - // We must clean up the config we just created - config->deleteLater(); - safeData->deleteLater(); - } + } else { + // CAS failed - state changed (e.g., set to Destroyed) + // We must clean up the config we just created + config->deleteLater(); + safeData->deleteLater(); + } + }, Qt::QueuedConnection); }); } )";