1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QFUTUREINTERFACE_P_H
5#define QFUTUREINTERFACE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/private/qglobal_p.h>
19#include <QtCore/qelapsedtimer.h>
20#include <QtCore/qcoreevent.h>
21#include <QtCore/qlist.h>
22#include <QtCore/qwaitcondition.h>
23#include <QtCore/qrunnable.h>
24#include <QtCore/qthreadpool.h>
25#include <QtCore/qfutureinterface.h>
26#include <QtCore/qexception.h>
27
28QT_REQUIRE_CONFIG(future);
29
30QT_BEGIN_NAMESPACE
31
32// Although QFutureCallOutEvent and QFutureCallOutInterface are private,
33// for historical reasons they were used externally (in QtJambi, see
34// https://github.com/OmixVisualization/qtjambi), so we export them to
35// not break the pre-existing code.
36class Q_CORE_EXPORT QFutureCallOutEvent : public QEvent
37{
38 Q_DECL_EVENT_COMMON(QFutureCallOutEvent)
39public:
40 enum CallOutType {
41 Started,
42 Finished,
43 Canceled,
44 Suspending,
45 Suspended,
46 Resumed,
47 Progress,
48 ProgressRange,
49 ResultsReady
50 };
51
52 QFutureCallOutEvent()
53 : QEvent(QEvent::FutureCallOut), callOutType(CallOutType(0)), index1(-1), index2(-1)
54 { }
55 explicit QFutureCallOutEvent(CallOutType callOutType, int index1 = -1)
56 : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(-1)
57 { }
58 QFutureCallOutEvent(CallOutType callOutType, int index1, int index2)
59 : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(index2)
60 { }
61
62 QFutureCallOutEvent(CallOutType callOutType, int index1, const QString &text)
63 : QEvent(QEvent::FutureCallOut),
64 callOutType(callOutType),
65 index1(index1),
66 index2(-1),
67 text(text)
68 { }
69
70 CallOutType callOutType;
71 int index1;
72 int index2;
73 QString text;
74};
75
76class Q_CORE_EXPORT QFutureCallOutInterface
77{
78public:
79 virtual ~QFutureCallOutInterface();
80 virtual void postCallOutEvent(const QFutureCallOutEvent &) = 0;
81 virtual void callOutInterfaceDisconnected() = 0;
82};
83
84class QFutureInterfaceBasePrivate
85{
86public:
87 QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState);
88 ~QFutureInterfaceBasePrivate();
89
90 // When the last QFuture<T> reference is removed, we need to make
91 // sure that data stored in the ResultStore is cleaned out.
92 // Since QFutureInterfaceBasePrivate can be shared between QFuture<T>
93 // and QFuture<void> objects, we use a separate ref. counter
94 // to keep track of QFuture<T> objects.
95 class RefCount
96 {
97 public:
98 inline RefCount(int r = 0, int rt = 0)
99 : m_refCount(r), m_refCountT(rt) {}
100 // Default ref counter for QFIBP
101 inline bool ref() { return m_refCount.ref(); }
102 inline bool deref() { return m_refCount.deref(); }
103 inline int load() const { return m_refCount.loadRelaxed(); }
104 // Ref counter for type T
105 inline bool refT() { return m_refCountT.ref(); }
106 inline bool derefT() { return m_refCountT.deref(); }
107 inline int loadT() const { return m_refCountT.loadRelaxed(); }
108
109 private:
110 QAtomicInt m_refCount;
111 QAtomicInt m_refCountT;
112 };
113
114 // T: accessed from executing thread
115 // Q: accessed from the waiting/querying thread
116 mutable QMutex m_mutex;
117 QBasicMutex continuationMutex;
118 QList<QFutureCallOutInterface *> outputConnections;
119 QElapsedTimer progressTime;
120 QWaitCondition waitCondition;
121 QWaitCondition pausedWaitCondition;
122
123 union Data {
124 QtPrivate::ResultStoreBase m_results;
125 QtPrivate::ExceptionStore m_exceptionStore;
126
127#ifndef QT_NO_EXCEPTIONS
128 void setException(const std::exception_ptr &e)
129 {
130 m_results.~ResultStoreBase();
131 new (&m_exceptionStore) QtPrivate::ExceptionStore();
132 m_exceptionStore.setException(e);
133 }
134#endif
135
136 ~Data() { }
137 };
138 Data data = { .m_results: QtPrivate::ResultStoreBase() };
139
140 QRunnable *runnable = nullptr;
141 QThreadPool *m_pool = nullptr;
142 // Wrapper for continuation
143 std::function<void(const QFutureInterfaceBase &)> continuation;
144 QFutureInterfaceBasePrivate *continuationData = nullptr;
145
146 RefCount refCount = 1;
147 QAtomicInt state; // reads and writes can happen unprotected, both must be atomic
148
149 int m_progressValue = 0; // TQ
150 struct ProgressData
151 {
152 int minimum = 0; // TQ
153 int maximum = 0; // TQ
154 QString text;
155 };
156 QScopedPointer<ProgressData> m_progress;
157
158 int m_expectedResultCount = 0;
159 bool launchAsync = false;
160 bool isValid = false;
161 bool hasException = false;
162
163 enum ContinuationState : quint8 { Default, Canceled, Cleaned };
164 std::atomic<ContinuationState> continuationState { Default };
165
166 inline QThreadPool *pool() const
167 { return m_pool ? m_pool : QThreadPool::globalInstance(); }
168
169 // Internal functions that does not change the mutex state.
170 // The mutex must be locked when calling these.
171 int internal_resultCount() const;
172 bool internal_isResultReadyAt(int index) const;
173 bool internal_waitForNextResult();
174 bool internal_updateProgressValue(int progress);
175 bool internal_updateProgress(int progress, const QString &progressText = QString());
176 void internal_setThrottled(bool enable);
177 void sendCallOut(const QFutureCallOutEvent &callOut);
178 void sendCallOuts(const QFutureCallOutEvent &callOut1, const QFutureCallOutEvent &callOut2);
179 void connectOutputInterface(QFutureCallOutInterface *iface);
180 void disconnectOutputInterface(QFutureCallOutInterface *iface);
181
182 void setState(QFutureInterfaceBase::State state);
183};
184
185QT_END_NAMESPACE
186
187#endif
188

source code of qtbase/src/corelib/thread/qfutureinterface_p.h