From f53886e91afe4e8cbabc85b182a20189f8099260 Mon Sep 17 00:00:00 2001 From: TuQinggang Date: Wed, 2 Sep 2020 09:54:56 +0000 Subject: [PATCH] New upstream Version 5.2.2.5 --- debian/changelog | 2 +- debian/compat | 2 +- debian/control | 2 +- debian/rules | 2 +- rpm/dtkcore.spec | 75 ++++++++++ src/util/DThreadUtils | 1 + src/util/dthreadutils.cpp | 63 +++++++++ src/util/dthreadutils.h | 174 ++++++++++++++++++++++++ src/util/util.pri | 9 +- tests/dthreadutils/dthreadutils.pro | 25 ++++ tests/dthreadutils/tst_dthreadutils.cpp | 87 ++++++++++++ tests/tests.pro | 3 +- 12 files changed, 437 insertions(+), 8 deletions(-) create mode 100644 rpm/dtkcore.spec create mode 100644 src/util/DThreadUtils create mode 100644 src/util/dthreadutils.cpp create mode 100644 src/util/dthreadutils.h create mode 100644 tests/dthreadutils/dthreadutils.pro create mode 100644 tests/dthreadutils/tst_dthreadutils.cpp diff --git a/debian/changelog b/debian/changelog index 63463dc..88df8f3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,7 +2,7 @@ dtkcore (5.0.3) unstable; urgency=medium * Release 5.0.3 - -- Deepin Packages Builder Tue, 21 Sep 2019 13:31:03 +0800 + -- Deepin Packages Builder Sat, 21 Sep 2019 13:31:03 +0800 dtkcore (5.0.0) unstable; urgency=medium diff --git a/debian/compat b/debian/compat index ec63514..48082f7 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 +12 diff --git a/debian/control b/debian/control index 0a5dde2..9c46a7e 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: dtkcore Section: libdevel Priority: optional Maintainer: Deepin Packages Builder -Build-Depends: debhelper (>= 9), pkg-config, +Build-Depends: debhelper (>= 12), pkg-config, qttools5-dev-tools, qtbase5-private-dev, libgsettings-qt-dev Standards-Version: 3.9.8 diff --git a/debian/rules b/debian/rules index d13bf0f..d911e37 100755 --- a/debian/rules +++ b/debian/rules @@ -19,7 +19,7 @@ endif endif %: - dh $@ --parallel + dh $@ override_dh_auto_configure: dh_auto_configure -- LIB_INSTALL_DIR=/usr/lib/$(DEB_HOST_MULTIARCH) VERSION=$(CONFIG_VERSION) diff --git a/rpm/dtkcore.spec b/rpm/dtkcore.spec new file mode 100644 index 0000000..5358875 --- /dev/null +++ b/rpm/dtkcore.spec @@ -0,0 +1,75 @@ +Name: dtkcore +Version: 5.2.2.3 +Release: 1%{?dist} +Summary: Deepin tool kit core modules +License: GPLv3 +URL: https://github.com/linuxdeepin/dtkcore +Source0: %{name}_%{version}.orig.tar.xz +BuildRequires: gcc-c++ +BuildRequires: annobin +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(gsettings-qt) +Obsoletes: deepin-tool-kit <= 0.3.3 +Obsoletes: deepin-tool-kit-devel <= 0.3.3 +Obsoletes: dtksettings <= 0.1.7 +Obsoletes: dtksettings-devel <= 0.1.7 + +%description +Deepin tool kit core modules. + +%package devel +Summary: Development package for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: qt5-qtbase-devel + +%description devel +Header files and libraries for %{name}. + +%prep +%setup -q + +sed -i 's|/lib|/libexec|' tools/settings/settings.pro +## consider relying on %%_qt5_bindir (see %%build below) instead of patching -- rex +#sed -i 's|qmake|qmake-qt5|' src/dtk_module.prf +#sed -i 's|lrelease|lrelease-qt5|' tools/script/dtk-translate.py src/dtk_translation.prf + +%build +# help find (and prefer) qt5 utilities, e.g. qmake, lrelease +export PATH=%{_qt5_bindir}:$PATH +%qmake_qt5 PREFIX=%{_prefix} \ + DTK_VERSION=%{version} \ + LIB_INSTALL_DIR=%{_libdir} \ + BIN_INSTALL_DIR=%{_libexecdir}/dtk5 \ + TOOL_INSTALL_DIR=%{_libexecdir}/dtk5 +%make_build + +%install +%make_install INSTALL_ROOT=%{buildroot} + +%ldconfig_scriptlets + +%files +%doc README.md +%license LICENSE +%{_libdir}/libdtkcore.so.* +%{_libexecdir}/dtk5/dtk-settings +%{_libexecdir}/dtk5/dtk-license.py* +%{_libexecdir}/dtk5/dtk-translate.py* +%{_libexecdir}/dtk5/deepin-os-release + +%files devel +%doc doc/Specification.md +%{_includedir}/libdtk-*/ +%{_qt5_archdatadir}/mkspecs/features/*.prf +%{_qt5_archdatadir}/mkspecs/modules/*.pri +%{_libdir}/cmake/Dtk/ +%{_libdir}/cmake/DtkCore/ +%{_libdir}/cmake/DtkCMake/ +%{_libdir}/cmake/DtkTools/ +%{_libdir}/pkgconfig/dtkcore.pc +%{_libdir}/libdtkcore.so +/usr/share/glib-2.0/schemas/* + +%changelog +* Thu Jun 11 2020 uoser - 5.2.2.3 +- Update to 5.2.2.3 diff --git a/src/util/DThreadUtils b/src/util/DThreadUtils new file mode 100644 index 0000000..13b83d8 --- /dev/null +++ b/src/util/DThreadUtils @@ -0,0 +1 @@ +#include "dthreadutils.h" diff --git a/src/util/dthreadutils.cpp b/src/util/dthreadutils.cpp new file mode 100644 index 0000000..e459129 --- /dev/null +++ b/src/util/dthreadutils.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 ~ 2020 Deepin Technology Co., Ltd. + * + * Author: zccrs + * + * Maintainer: zccrs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dthreadutils.h" + +DCORE_BEGIN_NAMESPACE + +namespace DThreadUtil { +FunctionCallProxy::FunctionCallProxy(QThread *thread) +{ + qRegisterMetaType>(); + + connect(this, &FunctionCallProxy::callInLiveThread, this, [] (QSemaphore *s, QPointer target, FunctionType *func) { + if (Q_LIKELY(target)) { + (*func)(); + } else { + qWarning() << "DThreadUtils::runInThread:" << "The target object is destoryed"; + } + + s->release(); + }, Qt::QueuedConnection); + connect(thread, &QThread::finished, this, [this] { + qWarning() << "DThreadUtils::runInThread:" << sender() << "the thread finished"; + }, Qt::DirectConnection); +} + +void FunctionCallProxy::proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun) +{ + if (QThread::currentThread() == thread) + return fun(); + + FunctionCallProxy proxy(thread); + proxy.moveToThread(thread); + + // 如果线程未开启事件循环,且不是主线程,则需要给出严重警告信息,因为可能会导致死锁 + if (thread->loopLevel() <= 0 && (!QCoreApplication::instance() || thread != QCoreApplication::instance()->thread())) { + qCritical() << Q_FUNC_INFO << thread << ", the thread no event loop"; + } + + proxy.callInLiveThread(s, target ? target : &proxy, &fun); + s->acquire(); +} +} // end namespace DThreadUtil + +DCORE_END_NAMESPACE diff --git a/src/util/dthreadutils.h b/src/util/dthreadutils.h new file mode 100644 index 0000000..3b1609a --- /dev/null +++ b/src/util/dthreadutils.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2020 ~ 2020 Deepin Technology Co., Ltd. + * + * Author: zccrs + * + * Maintainer: zccrs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef DTHREADUTILS_H +#define DTHREADUTILS_H + +#include +#include +#include +#include +#include +#include +#include + +DCORE_BEGIN_NAMESPACE + +namespace DThreadUtil { +typedef std::function FunctionType; + +class FunctionCallProxy : public QObject +{ + Q_OBJECT +public: + explicit FunctionCallProxy(QThread *thread); + + static void proxyCall(QSemaphore *s, QThread *thread, QObject *target, FunctionType fun); + +Q_SIGNALS: + void callInLiveThread(QSemaphore *s, QPointer target, FunctionType *func); +}; + +template +class _TMP +{ +public: + inline static ReturnType runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function fun) + { + ReturnType result; + FunctionType proxyFun = [&result, &fun] () { + result = fun(); + }; + + FunctionCallProxy::proxyCall(s, thread, target, proxyFun); + return result; + } + + template + inline static typename std::enable_if::value, ReturnType>::type + runInThread(QSemaphore *s, QThread *thread, T *, std::function fun) + { + return runInThread(s, thread, static_cast(nullptr), fun); + } +}; +template <> +class _TMP +{ +public: + inline static void runInThread(QSemaphore *s, QThread *thread, QObject *target, std::function fun) + { + FunctionCallProxy::proxyCall(s, thread, target, fun); + } + + template + inline static typename std::enable_if::value, void>::type + runInThread(QSemaphore *s, QThread *thread, T *, std::function fun) + { + return runInThread(s, thread, static_cast(nullptr), fun); + } +}; + +template +inline auto runInThread(QSemaphore *s, QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...)) +{ + return _TMP::runInThread(s, thread, target, std::bind(fun, std::forward(args)...)); +} +template +inline auto runInThread(QSemaphore *s, QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...)) +{ + return runInThread(s, thread, nullptr, fun, std::forward(args)...); +} +template +inline typename QtPrivate::FunctionPointer::ReturnType + runInThread(QSemaphore *s, QThread *thread, QObject *target, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) +{ + return _TMP::ReturnType>::runInThread(s, thread, target, std::bind(fun, obj, std::forward(args)...)); +} +template +inline typename QtPrivate::FunctionPointer::ReturnType + runInThread(QSemaphore *s, QThread *thread, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) +{ + return _TMP::ReturnType>::runInThread(s, thread, obj, std::bind(fun, obj, std::forward(args)...)); +} + +template +inline auto runInThread(QThread *thread, QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...)) +{ + QSemaphore s; + + return runInThread(&s, thread, target, fun, std::forward(args)...); +} +template +inline auto runInThread(QThread *thread, Fun fun, Args&&... args) -> decltype(fun(args...)) +{ + return runInThread(thread, nullptr, fun, std::forward(args)...); +} +template +inline typename QtPrivate::FunctionPointer::ReturnType + runInThread(QThread *thread, T *target, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) +{ + QSemaphore s; + + return runInThread(&s, thread, target, obj, fun, std::forward(args)...); +} + +template +inline typename QtPrivate::FunctionPointer::ReturnType + runInThread(QThread *thread, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) +{ + return runInThread(thread, obj, obj, fun, std::forward(args)...); +} + +template +inline auto runInMainThread(QObject *target, Fun fun, Args&&... args) -> decltype(fun(args...)) +{ + if (!QCoreApplication::instance()) { + return fun(std::forward(args)...); + } + + return runInThread(QCoreApplication::instance()->thread(), target, fun, std::forward(args)...); +} +template +inline auto runInMainThread(Fun fun, Args&&... args) -> decltype(fun(args...)) +{ + return runInMainThread(nullptr, fun, std::forward(args)...); +} + +template +inline typename QtPrivate::FunctionPointer::ReturnType + runInMainThread(T *target, typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) +{ + if (!QCoreApplication::instance()) { + return (obj->*fun)(std::forward(args)...); + } + + return runInThread(QCoreApplication::instance()->thread(), target, obj, fun, std::forward(args)...); +} +template +inline typename QtPrivate::FunctionPointer::ReturnType + runInMainThread(typename QtPrivate::FunctionPointer::Object *obj, Fun fun, Args&&... args) +{ + return runInMainThread(obj, obj, fun, std::forward(args)...); +} +} + +DCORE_END_NAMESPACE + +#endif // DTHREADUTILS_H diff --git a/src/util/util.pri b/src/util/util.pri index a45dea8..3f2353c 100644 --- a/src/util/util.pri +++ b/src/util/util.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/dnotifysender.h \ $$PWD/dexportedinterface.h \ $$PWD/dvtablehook.h \ - $$PWD/dfileservices.h + $$PWD/dfileservices.h \ + $$PWD/dthreadutils.h INCLUDEPATH += $$PWD @@ -22,7 +23,8 @@ includes.files += \ $$PWD/DNotifySender \ $$PWD/DExportedInterface \ $$PWD/DVtableHook \ - $$PWD/DFileServices + $$PWD/DFileServices \ + $$PWD/DThreadUtils RESOURCES += \ $$PWD/util.qrc @@ -36,7 +38,8 @@ SOURCES += \ $$PWD/dnotifysender.cpp \ $$PWD/dpinyin.cpp \ $$PWD/dexportedinterface.cpp \ - $$PWD/dvtablehook.cpp + $$PWD/dvtablehook.cpp \ + $$PWD/dthreadutils.cpp linux { QT += dbus diff --git a/tests/dthreadutils/dthreadutils.pro b/tests/dthreadutils/dthreadutils.pro new file mode 100644 index 0000000..aa6af36 --- /dev/null +++ b/tests/dthreadutils/dthreadutils.pro @@ -0,0 +1,25 @@ +QT += testlib concurrent +QT -= gui + +TEMPLATE = app +CONFIG += c++11 + +!isEmpty(DTK_STATIC_LIB){ + DEFINES += DTK_STATIC_LIB +} + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../src/release/ -ldtkcore +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../src/debug/ -ldtkcore +else:unix: LIBS += -L$$OUT_PWD/../../src/ -ldtkcore + +INCLUDEPATH += $$PWD/../../src +DEPENDPATH += $$PWD/../../src + +CONFIG(debug, debug|release) { + unix:QMAKE_RPATHDIR += $$OUT_PWD/../../src +} + +QMAKE_LFLAGS += -Wl,--export-dynamic + +SOURCES += \ + tst_dthreadutils.cpp diff --git a/tests/dthreadutils/tst_dthreadutils.cpp b/tests/dthreadutils/tst_dthreadutils.cpp new file mode 100644 index 0000000..b25c8fc --- /dev/null +++ b/tests/dthreadutils/tst_dthreadutils.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 ~ 2020 Deepin Technology Co., Ltd. + * + * Author: zccrs + * + * Maintainer: zccrs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include + +DCORE_USE_NAMESPACE + +class tst_DThreadUtils : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testCallInMainThread(); +}; + +void tst_DThreadUtils::testCallInMainThread() +{ + QVERIFY(DThreadUtil::runInMainThread([] { + return QThread::currentThread() == QCoreApplication::instance()->thread(); + })); + + auto result = QtConcurrent::run([] { + QThread *t = QThread::currentThread(); + QVERIFY(DThreadUtil::runInMainThread([] (QThread *thread) { + return QThread::currentThread() == QCoreApplication::instance()->thread() && QThread::currentThread() != thread; + }, t)); + }); + + QVERIFY(QTest::qWaitFor([&] { + return result.isFinished(); + })); + + { + // 测试target对象销毁后是否还会触发函数调用 + QPointer object = new QObject(); + bool test = true; + auto result1 = QtConcurrent::run([&test, object] { + DThreadUtil::runInMainThread(object, [&test, object] () { + if (!object) + return false; + + delete object.data(); + return true; + }); + }); + auto result2 = QtConcurrent::run([&test, object] { + DThreadUtil::runInMainThread(object, [&test, object] () { + if (!object) + return false; + + delete object.data(); + return true; + }); + }); + + QVERIFY(QTest::qWaitFor([&] { + return result1.isFinished() && result2.isFinished(); + })); + QVERIFY(test); + } +} + +QTEST_MAIN(tst_DThreadUtils) + +#include "tst_dthreadutils.moc" diff --git a/tests/tests.pro b/tests/tests.pro index d37cc25..2a5e2de 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -2,4 +2,5 @@ TEMPLATE = subdirs SUBDIRS += \ dutils \ dvtablehook \ - ddesktopentry + ddesktopentry \ + dthreadutils -- 2.30.2