// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QFUTUREINTERFACE_P_H #define QFUTUREINTERFACE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include #include #include #include #include QT_REQUIRE_CONFIG(future); QT_BEGIN_NAMESPACE // Although QFutureCallOutEvent and QFutureCallOutInterface are private, // for historical reasons they were used externally (in QtJambi, see // https://github.com/OmixVisualization/qtjambi), so we export them to // not break the pre-existing code. class Q_CORE_EXPORT QFutureCallOutEvent : public QEvent { Q_DECL_EVENT_COMMON(QFutureCallOutEvent) public: enum CallOutType { Started, Finished, Canceled, Suspending, Suspended, Resumed, Progress, ProgressRange, ResultsReady }; QFutureCallOutEvent() : QEvent(QEvent::FutureCallOut), callOutType(CallOutType(0)), index1(-1), index2(-1) { } explicit QFutureCallOutEvent(CallOutType callOutType, int index1 = -1) : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(-1) { } QFutureCallOutEvent(CallOutType callOutType, int index1, int index2) : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(index2) { } QFutureCallOutEvent(CallOutType callOutType, int index1, const QString &text) : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(-1), text(text) { } CallOutType callOutType; int index1; int index2; QString text; }; class Q_CORE_EXPORT QFutureCallOutInterface { public: virtual ~QFutureCallOutInterface(); virtual void postCallOutEvent(const QFutureCallOutEvent &) = 0; virtual void callOutInterfaceDisconnected() = 0; }; class QFutureInterfaceBasePrivate { public: QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState); ~QFutureInterfaceBasePrivate(); // When the last QFuture reference is removed, we need to make // sure that data stored in the ResultStore is cleaned out. // Since QFutureInterfaceBasePrivate can be shared between QFuture // and QFuture objects, we use a separate ref. counter // to keep track of QFuture objects. class RefCount { public: inline RefCount(int r = 0, int rt = 0) : m_refCount(r), m_refCountT(rt) {} // Default ref counter for QFIBP inline bool ref() { return m_refCount.ref(); } inline bool deref() { return m_refCount.deref(); } inline int load() const { return m_refCount.loadRelaxed(); } // Ref counter for type T inline bool refT() { return m_refCountT.ref(); } inline bool derefT() { return m_refCountT.deref(); } inline int loadT() const { return m_refCountT.loadRelaxed(); } private: QAtomicInt m_refCount; QAtomicInt m_refCountT; }; // T: accessed from executing thread // Q: accessed from the waiting/querying thread mutable QMutex m_mutex; QBasicMutex continuationMutex; QList outputConnections; QElapsedTimer progressTime; QWaitCondition waitCondition; QWaitCondition pausedWaitCondition; union Data { QtPrivate::ResultStoreBase m_results; QtPrivate::ExceptionStore m_exceptionStore; #ifndef QT_NO_EXCEPTIONS void setException(const std::exception_ptr &e) { m_results.~ResultStoreBase(); new (&m_exceptionStore) QtPrivate::ExceptionStore(); m_exceptionStore.setException(e); } #endif ~Data() { } }; Data data = { QtPrivate::ResultStoreBase() }; QRunnable *runnable = nullptr; QThreadPool *m_pool = nullptr; // Wrapper for continuation std::function continuation; QFutureInterfaceBasePrivate *continuationData = nullptr; RefCount refCount = 1; QAtomicInt state; // reads and writes can happen unprotected, both must be atomic int m_progressValue = 0; // TQ struct ProgressData { int minimum = 0; // TQ int maximum = 0; // TQ QString text; }; QScopedPointer m_progress; int m_expectedResultCount = 0; bool launchAsync = false; bool isValid = false; bool hasException = false; enum ContinuationState : quint8 { Default, Canceled, Cleaned }; std::atomic continuationState { Default }; inline QThreadPool *pool() const { return m_pool ? m_pool : QThreadPool::globalInstance(); } // Internal functions that does not change the mutex state. // The mutex must be locked when calling these. int internal_resultCount() const; bool internal_isResultReadyAt(int index) const; bool internal_waitForNextResult(); bool internal_updateProgressValue(int progress); bool internal_updateProgress(int progress, const QString &progressText = QString()); void internal_setThrottled(bool enable); void sendCallOut(const QFutureCallOutEvent &callOut); void sendCallOuts(const QFutureCallOutEvent &callOut1, const QFutureCallOutEvent &callOut2); void connectOutputInterface(QFutureCallOutInterface *iface); void disconnectOutputInterface(QFutureCallOutInterface *iface); void setState(QFutureInterfaceBase::State state); }; QT_END_NAMESPACE #endif