diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aa457f..f512b83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,78 +1,78 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.64.0") # handled by release scripts project(ThreadWeaver VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.63.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) set(REQUIRED_QT_VERSION 5.11.0) find_package(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) - -include(GenerateExportHeader) - +include(ECMGenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMAddQch) +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") + option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX THREADWEAVER VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/threadweaver_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5ThreadWeaverConfigVersion.cmake" SOVERSION 5) # -- add_definitions(-DQT_NO_FOREACH) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(benchmarks) endif() add_subdirectory(examples) # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5ThreadWeaver") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5ThreadWeaver_QCH FILE KF5ThreadWeaverQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5ThreadWeaverQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5ThreadWeaverConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5ThreadWeaverConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/threadweaver_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5ThreadWeaverConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5ThreadWeaverConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5ThreadWeaverTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5ThreadWeaverTargets.cmake NAMESPACE KF5:: ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 92159b1..3915839 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,129 +1,136 @@ ########### next target ############### set(ThreadWeaver_LIB_SRCS queuesignals.cpp queuesignals_p.cpp queuestream.cpp queueapi.cpp exception.cpp queue.cpp weaver.cpp weaver_p.cpp debuggingaids.cpp thread.cpp job.cpp job_p.cpp iddecorator.cpp qobjectdecorator.cpp executor.cpp executewrapper.cpp state.cpp weaverimplstate.cpp inconstructionstate.cpp workinghardstate.cpp suspendingstate.cpp suspendedstate.cpp shuttingdownstate.cpp destructedstate.cpp collection.cpp collection_p.cpp sequence.cpp sequence_p.cpp dependencypolicy.cpp dependency.cpp resourcerestrictionpolicy.cpp ) add_library(KF5ThreadWeaver ${ThreadWeaver_LIB_SRCS}) -generate_export_header(KF5ThreadWeaver BASE_NAME ThreadWeaver) add_library(KF5::ThreadWeaver ALIAS KF5ThreadWeaver) +ecm_generate_export_header(KF5ThreadWeaver + BASE_NAME ThreadWeaver + # GROUP_BASE_NAME KF <- enable once all of KF modules use ecm_generate_export_header + VERSION ${KF5_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.0 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) target_link_libraries(KF5ThreadWeaver PUBLIC Qt5::Core) set(threadweaver_BUILD_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(KF5ThreadWeaver PUBLIC "$") target_include_directories(KF5ThreadWeaver INTERFACE "$") #FIXME: make this PUBLIC, so that it applies to anything that links against kde_target_enable_exceptions(KF5ThreadWeaver PRIVATE) set_target_properties(KF5ThreadWeaver PROPERTIES VERSION ${THREADWEAVER_VERSION_STRING} SOVERSION ${THREADWEAVER_SOVERSION} EXPORT_NAME ThreadWeaver ) install(TARGETS KF5ThreadWeaver EXPORT KF5ThreadWeaverTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) ecm_generate_headers(ThreadWeaver_CamelCase_HEADERS HEADER_NAMES ThreadWeaver Weaver WeaverInterface QueueAPI QueueStream Queueing Exception QueueInterface Queue DebuggingAids Thread JobInterface Job IdDecorator QObjectDecorator Lambda State WeaverImplState InConstructionState WorkingHardState SuspendingState SuspendedState ShuttingDownState DestructedState Collection Sequence Dependency DependencyPolicy ResourceRestrictionPolicy QueueSignals QueuePolicy JobPointer ManagedJobPointer PREFIX ThreadWeaver REQUIRED_HEADERS ThreadWeaver_HEADERS ) install(FILES ${ThreadWeaver_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/ThreadWeaver/ThreadWeaver COMPONENT Devel) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/threadweaver_export.h ${ThreadWeaver_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/ThreadWeaver/threadweaver COMPONENT Devel ) if(BUILD_QCH) ecm_add_qch( KF5ThreadWeaver_QCH NAME ThreadWeaver BASE_NAME KF5ThreadWeaver VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${ThreadWeaver_HEADERS} "${CMAKE_SOURCE_DIR}/docs/use-cases.md" "${CMAKE_SOURCE_DIR}/docs/whymultithreading.md" MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS Qt5Core_QCH INCLUDE_DIRS ${threadweaver_BUILD_INCLUDE_DIRS} BLANK_MACROS THREADWEAVER_EXPORT THREADWEAVER_DEPRECATED THREADWEAVER_DEPRECATED_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME ThreadWeaver LIB_NAME KF5ThreadWeaver DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/ThreadWeaver) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/collection.cpp b/src/collection.cpp index d00c56e..cbe2fdc 100644 --- a/src/collection.cpp +++ b/src/collection.cpp @@ -1,213 +1,215 @@ /* -*- C++ -*- This file implements the Collection class. $ Author: Mirko Boehm $ $ Copyright: (C) 2004-2013 Mirko Boehm $ $ Contact: mirko@kde.org http://www.kde.org http://creative-destruction.me $ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "collection.h" #include "queueapi.h" #include "debuggingaids.h" #include "queueing.h" #include "collection_p.h" #include #include #include #include "dependencypolicy.h" #include "executewrapper_p.h" #include "thread.h" namespace ThreadWeaver { class CollectionExecuteWrapper : public ExecuteWrapper { public: CollectionExecuteWrapper() : collection(nullptr) {} void setCollection(Collection *collection_) { collection = collection_; } void begin(const JobPointer& job, Thread *thread) override { TWDEBUG(4, "CollectionExecuteWrapper::begin: collection %p\n", collection); ExecuteWrapper::begin(job, thread); Q_ASSERT(collection); collection->d()->elementStarted(collection, job, thread); ExecuteWrapper::begin(job, thread); } void end(const JobPointer& job, Thread *thread) override { TWDEBUG(4, "CollectionExecuteWrapper::end: collection %p\n", collection); Q_ASSERT(collection); ExecuteWrapper::end(job, thread); collection->d()->elementFinished(collection, job, thread); } void cleanup(const JobPointer& job, Thread *) override { //Once job is unwrapped from us, this object is dangling. Job::executor points to the next higher up execute wrapper. //It is thus safe to "delete this". By no means add any later steps after delete! delete unwrap(job); } private: ThreadWeaver::Collection *collection; }; Collection::Collection() : Job(new Private::Collection_Private) { } Collection::Collection(Private::Collection_Private *d__) : Job(d__) { } Collection::~Collection() { MUTEX_ASSERT_UNLOCKED(mutex()); // dequeue all remaining jobs: QMutexLocker l(mutex()); Q_UNUSED(l); if (d()->api != nullptr) { // still queued d()->dequeueElements(this, false); } } void Collection::addJob(JobPointer job) { QMutexLocker l(mutex()); Q_UNUSED(l); REQUIRE(d()->api == nullptr || d()->selfIsExecuting == true); // not queued yet or still running REQUIRE(job != nullptr); CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper(); wrapper->setCollection(this); wrapper->wrap(job->setExecutor(wrapper)); d()->elements.append(job); } void Collection::stop(JobPointer job) { Q_UNUSED(job); QMutexLocker l(mutex()); Q_UNUSED(l); d()->stop_locked(this); } void Collection::aboutToBeQueued_locked(QueueAPI *api) { Q_ASSERT(!mutex()->tryLock()); Q_ASSERT(d()->api == nullptr); // never queue twice d()->api = api; d()->selfExecuteWrapper.wrap(setExecutor(&d()->selfExecuteWrapper)); CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper(); wrapper->setCollection(this); wrapper->wrap(setExecutor(wrapper)); Job::aboutToBeQueued_locked(api); } void Collection::aboutToBeDequeued_locked(QueueAPI *api) { Q_ASSERT(!mutex()->tryLock()); Q_ASSERT(api && d()->api == api); d()->dequeueElements(this, true); d()->api = nullptr; Job::aboutToBeDequeued_locked(api); } void Collection::execute(const JobPointer& job, Thread *thread) { { QMutexLocker l(mutex()); Q_UNUSED(l); Q_ASSERT(d()->self.isNull()); Q_ASSERT(d()->api != nullptr); d()->self = job; d()->selfIsExecuting = true; // reset in elementFinished } Job::execute(job, thread); } void Collection::run(JobPointer, Thread *) { //empty } Private::Collection_Private *Collection::d() { return reinterpret_cast(Job::d()); } const Private::Collection_Private *Collection::d() const { return reinterpret_cast(Job::d()); } JobPointer Collection::jobAt(int i) { Q_ASSERT(!mutex()->tryLock()); Q_ASSERT(i >= 0 && i < d()->elements.size()); return d()->elements.at(i); } int Collection::elementCount() const { QMutexLocker l(mutex()); Q_UNUSED(l); return jobListLength_locked(); } +#if THREADWEAVER_BUILD_DEPRECATED_SINCE(5, 0) int Collection::jobListLength() const { QMutexLocker l(mutex()); Q_UNUSED(l); return jobListLength_locked(); } +#endif int Collection::jobListLength_locked() const { return d()->elements.size(); } Collection &Collection::operator<<(JobInterface *job) { addJob(make_job(job)); return *this; } Collection &Collection::operator<<(const JobPointer &job) { addJob(job); return *this; } Collection &Collection::operator<<(JobInterface &job) { addJob(make_job_raw(&job)); return *this; } } diff --git a/src/collection.h b/src/collection.h index 2c46b5a..ab8c7c2 100644 --- a/src/collection.h +++ b/src/collection.h @@ -1,115 +1,117 @@ /* -*- C++ -*- This file declares the Collection class. $ Author: Mirko Boehm $ $ Copyright: (C) 2004-2013 Mirko Boehm $ $ Contact: mirko@kde.org http://www.kde.org http://creative-destruction.me $ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef JOBCOLLECTION_H #define JOBCOLLECTION_H #include "job.h" #include "jobpointer.h" namespace ThreadWeaver { class Thread; class CollectionExecuteWrapper; namespace Private { class Collection_Private; } /** A Collection is a vector of Jobs that will be queued together. * In a Collection, the order of execution of the elements is not specified. * * It is intended that the collection is set up first and then * queued. After queuing, no further jobs should be added to the collection. */ class THREADWEAVER_EXPORT Collection : public Job { public: Collection(); Collection(ThreadWeaver::Private::Collection_Private * d); ~Collection() override; /** Append a job to the collection. * * To use Collection, create the Job objects first, add them to the collection, and then queue it. After * the collection has been queued, no further Jobs are supposed to be added. * * @note Once the job has been added, execute wrappers can no more be set on it */ virtual void addJob(JobPointer); /** Stop processing, dequeue all remaining Jobs. * job is supposed to be an element of the collection. */ //FIXME remove job argument? void stop(ThreadWeaver::JobPointer job); /** Return the number of elements in the collection. */ int elementCount() const; - //FIXME remove - /** @deprecated Use elementCount(). */ +#if THREADWEAVER_ENABLE_DEPRECATED_SINCE(5, 0) + /** @deprecated Since 5.0, use elementCount(). */ + THREADWEAVER_DEPRECATED_VERSION(5, 0, "Use Collection::elementCount()") int jobListLength() const; +#endif /** @brief Add the job to this collection by pointer. */ Collection &operator<<(ThreadWeaver::JobInterface *job); /** @brief Add the job to this collection. */ Collection &operator<<(const ThreadWeaver::JobPointer &job); Collection &operator<<(JobInterface &job); protected: /** Overload to queue the collection. */ void aboutToBeQueued_locked(QueueAPI *api) override; /** Overload to dequeue the collection. */ void aboutToBeDequeued_locked(QueueAPI *api) override; /** Return a ref-erence to the job in the job list at position i. */ JobPointer jobAt(int i); //FIXME remove /** Return the number of jobs in the joblist. * Assumes that the mutex is being held. */ virtual int jobListLength_locked() const; protected: /** Overload the execute method. */ void execute(const JobPointer& job, Thread *) override; /** Overload run(). * We have to. */ void run(JobPointer self, Thread *thread) override; protected: friend class CollectionExecuteWrapper; //needs to access d() friend class Collection_Private; ThreadWeaver::Private::Collection_Private* d(); const ThreadWeaver::Private::Collection_Private* d() const; }; } #endif