1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qfuturewatcher.h"
41 #include "qfuturewatcher_p.h"
42 
43 #include <QtCore/qcoreevent.h>
44 #include <QtCore/qcoreapplication.h>
45 #include <QtCore/qmetaobject.h>
46 #include <QtCore/qthread.h>
47 
48 QT_BEGIN_NAMESPACE
49 
50 /*! \class QFutureWatcher
51     \reentrant
52     \since 4.4
53 
54     \inmodule QtCore
55     \ingroup thread
56 
57     \brief The QFutureWatcher class allows monitoring a QFuture using signals
58     and slots.
59 
60     QFutureWatcher provides information and notifications about a QFuture. Use
61     the setFuture() function to start watching a particular QFuture. The
62     future() function returns the future set with setFuture().
63 
64     For convenience, several of QFuture's functions are also available in
65     QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(),
66     progressText(), isStarted(), isFinished(), isRunning(), isCanceled(),
67     isPaused(), waitForFinished(), result(), and resultAt(). The cancel(),
68     setPaused(), pause(), resume(), and togglePaused() functions are slots in
69     QFutureWatcher.
70 
71     Status changes are reported via the started(), finished(), canceled(),
72     paused(), resumed(), resultReadyAt(), and resultsReadyAt() signals.
73     Progress information is provided from the progressRangeChanged(),
74     void progressValueChanged(), and progressTextChanged() signals.
75 
76     Throttling control is provided by the setPendingResultsLimit() function.
77     When the number of pending resultReadyAt() or resultsReadyAt() signals
78     exceeds the limit, the computation represented by the future will be
79     throttled automatically. The computation will resume once the number of
80     pending signals drops below the limit.
81 
82     Example: Starting a computation and getting a slot callback when it's
83     finished:
84 
85     \snippet code/src_corelib_thread_qfuturewatcher.cpp 0
86 
87     Be aware that not all running asynchronous computations can be canceled or
88     paused. For example, the future returned by QtConcurrent::run() cannot be
89     canceled; but the future returned by QtConcurrent::mappedReduced() can.
90 
91     QFutureWatcher<void> is specialized to not contain any of the result
92     fetching functions. Any QFuture<T> can be watched by a
93     QFutureWatcher<void> as well. This is useful if only status or progress
94     information is needed; not the actual result data.
95 
96     \sa QFuture, {Qt Concurrent}
97 */
98 
99 /*! \fn template <typename T> QFutureWatcher<T>::QFutureWatcher(QObject *parent)
100 
101     Constructs a new QFutureWatcher with the given \a parent. Until a future is
102     set with setFuture(), the functions isStarted(), isCanceled(), and
103     isFinished() return \c true.
104 */
QFutureWatcherBase(QObject * parent)105 QFutureWatcherBase::QFutureWatcherBase(QObject *parent)
106     :QObject(*new QFutureWatcherBasePrivate, parent)
107 { }
108 
109 /*! \fn template <typename T> QFutureWatcher<T>::~QFutureWatcher()
110 
111     Destroys the QFutureWatcher.
112 */
113 
114 /*! \fn template <typename T> void QFutureWatcher<T>::cancel()
115 
116     Cancels the asynchronous computation represented by the future(). Note that
117     the cancelation is asynchronous. Use waitForFinished() after calling
118     cancel() when you need synchronous cancelation.
119 
120     Currently available results may still be accessed on a canceled QFuture,
121     but new results will \e not become available after calling this function.
122     Also, this QFutureWatcher will not deliver progress and result ready
123     signals once canceled. This includes the progressValueChanged(),
124     progressRangeChanged(), progressTextChanged(), resultReadyAt(), and
125     resultsReadyAt() signals.
126 
127     Be aware that not all running asynchronous computations can be canceled.
128     For example, the QFuture returned by QtConcurrent::run() cannot be
129     canceled; but the QFuture returned by QtConcurrent::mappedReduced() can.
130 */
cancel()131 void QFutureWatcherBase::cancel()
132 {
133     futureInterface().cancel();
134 }
135 
136 /*! \fn template <typename T> void QFutureWatcher<T>::setPaused(bool paused)
137 
138     If \a paused is true, this function pauses the asynchronous computation
139     represented by the future(). If the computation is already paused, this
140     function does nothing. This QFutureWatcher will stop delivering progress
141     and result ready signals while the future is paused. Signal delivery will
142     continue once the computation is resumed.
143 
144     If \a paused is false, this function resumes the asynchronous computation.
145     If the computation was not previously paused, this function does nothing.
146 
147     Be aware that not all computations can be paused. For example, the
148     QFuture returned by QtConcurrent::run() cannot be paused; but the QFuture
149     returned by QtConcurrent::mappedReduced() can.
150 
151     \sa pause(), resume(), togglePaused()
152 */
setPaused(bool paused)153 void QFutureWatcherBase::setPaused(bool paused)
154 {
155     futureInterface().setPaused(paused);
156 }
157 
158 /*! \fn template <typename T> void QFutureWatcher<T>::pause()
159 
160     Pauses the asynchronous computation represented by the future(). This is a
161     convenience method that simply calls setPaused(true).
162 
163     \sa resume()
164 */
pause()165 void QFutureWatcherBase::pause()
166 {
167     futureInterface().setPaused(true);
168 }
169 
170 /*! \fn template <typename T> void QFutureWatcher<T>::resume()
171 
172     Resumes the asynchronous computation represented by the future(). This is
173     a convenience method that simply calls setPaused(false).
174 
175     \sa pause()
176 */
resume()177 void QFutureWatcherBase::resume()
178 {
179     futureInterface().setPaused(false);
180 }
181 
182 /*! \fn template <typename T> void QFutureWatcher<T>::togglePaused()
183 
184     Toggles the paused state of the asynchronous computation. In other words,
185     if the computation is currently paused, calling this function resumes it;
186     if the computation is running, it becomes paused. This is a convenience
187     method for calling setPaused(!isPaused()).
188 
189     \sa setPaused(), pause(), resume()
190 */
togglePaused()191 void QFutureWatcherBase::togglePaused()
192 {
193     futureInterface().togglePaused();
194 }
195 
196 /*! \fn template <typename T> int QFutureWatcher<T>::progressValue() const
197 
198     Returns the current progress value, which is between the progressMinimum()
199     and progressMaximum().
200 
201     \sa progressMinimum(), progressMaximum()
202 */
progressValue() const203 int QFutureWatcherBase::progressValue() const
204 {
205     return futureInterface().progressValue();
206 }
207 
208 /*! \fn template <typename T> int QFutureWatcher<T>::progressMinimum() const
209 
210     Returns the minimum progressValue().
211 
212     \sa progressValue(), progressMaximum()
213 */
progressMinimum() const214 int QFutureWatcherBase::progressMinimum() const
215 {
216     return futureInterface().progressMinimum();
217 }
218 
219 /*! \fn template <typename T> int QFutureWatcher<T>::progressMaximum() const
220 
221     Returns the maximum progressValue().
222 
223     \sa progressValue(), progressMinimum()
224 */
progressMaximum() const225 int QFutureWatcherBase::progressMaximum() const
226 {
227     return futureInterface().progressMaximum();
228 }
229 
230 /*! \fn template <typename T> QString QFutureWatcher<T>::progressText() const
231 
232     Returns the (optional) textual representation of the progress as reported
233     by the asynchronous computation.
234 
235     Be aware that not all computations provide a textual representation of the
236     progress, and as such, this function may return an empty string.
237 */
progressText() const238 QString QFutureWatcherBase::progressText() const
239 {
240     return futureInterface().progressText();
241 }
242 
243 /*! \fn template <typename T> bool QFutureWatcher<T>::isStarted() const
244 
245     Returns \c true if the asynchronous computation represented by the future()
246     has been started, or if no future has been set; otherwise returns \c false.
247 */
isStarted() const248 bool QFutureWatcherBase::isStarted() const
249 {
250     return futureInterface().queryState(QFutureInterfaceBase::Started);
251 }
252 
253 /*! \fn template <typename T> bool QFutureWatcher<T>::isFinished() const
254 
255     Returns \c true if the asynchronous computation represented by the future()
256     has finished, or if no future has been set; otherwise returns \c false.
257 */
isFinished() const258 bool QFutureWatcherBase::isFinished() const
259 {
260     Q_D(const QFutureWatcherBase);
261     return d->finished;
262 }
263 
264 /*! \fn template <typename T> bool QFutureWatcher<T>::isRunning() const
265 
266     Returns \c true if the asynchronous computation represented by the future()
267     is currently running; otherwise returns \c false.
268 */
isRunning() const269 bool QFutureWatcherBase::isRunning() const
270 {
271     return futureInterface().queryState(QFutureInterfaceBase::Running);
272 }
273 
274 /*! \fn template <typename T> bool QFutureWatcher<T>::isCanceled() const
275 
276     Returns \c true if the asynchronous computation has been canceled with the
277     cancel() function, or if no future has been set; otherwise returns \c false.
278 
279     Be aware that the computation may still be running even though this
280     function returns \c true. See cancel() for more details.
281 */
isCanceled() const282 bool QFutureWatcherBase::isCanceled() const
283 {
284     return futureInterface().queryState(QFutureInterfaceBase::Canceled);
285 }
286 
287 /*! \fn template <typename T> bool QFutureWatcher<T>::isPaused() const
288 
289     Returns \c true if the asynchronous computation has been paused with the
290     pause() function; otherwise returns \c false.
291 
292     Be aware that the computation may still be running even though this
293     function returns \c true. See setPaused() for more details.
294 
295     \sa setPaused(), togglePaused()
296 */
isPaused() const297 bool QFutureWatcherBase::isPaused() const
298 {
299     return futureInterface().queryState(QFutureInterfaceBase::Paused);
300 }
301 
302 /*! \fn template <typename T> void QFutureWatcher<T>::waitForFinished()
303 
304     Waits for the asynchronous computation to finish (including cancel()ed
305     computations).
306 */
waitForFinished()307 void QFutureWatcherBase::waitForFinished()
308 {
309     futureInterface().waitForFinished();
310 }
311 
event(QEvent * event)312 bool QFutureWatcherBase::event(QEvent *event)
313 {
314     Q_D(QFutureWatcherBase);
315     if (event->type() == QEvent::FutureCallOut) {
316         QFutureCallOutEvent *callOutEvent = static_cast<QFutureCallOutEvent *>(event);
317 
318         if (futureInterface().isPaused()) {
319             d->pendingCallOutEvents.append(callOutEvent->clone());
320             return true;
321         }
322 
323         if (callOutEvent->callOutType == QFutureCallOutEvent::Resumed
324             && !d->pendingCallOutEvents.isEmpty()) {
325             // send the resume
326             d->sendCallOutEvent(callOutEvent);
327 
328             // next send all pending call outs
329             for (int i = 0; i < d->pendingCallOutEvents.count(); ++i)
330                 d->sendCallOutEvent(d->pendingCallOutEvents.at(i));
331             qDeleteAll(d->pendingCallOutEvents);
332             d->pendingCallOutEvents.clear();
333         } else {
334             d->sendCallOutEvent(callOutEvent);
335         }
336         return true;
337     }
338     return QObject::event(event);
339 }
340 
341 /*! \fn template <typename T> void QFutureWatcher<T>::setPendingResultsLimit(int limit)
342 
343     The setPendingResultsLimit() provides throttling control. When the number
344     of pending resultReadyAt() or resultsReadyAt() signals exceeds the
345     \a limit, the computation represented by the future will be throttled
346     automatically. The computation will resume once the number of pending
347     signals drops below the \a limit.
348 */
setPendingResultsLimit(int limit)349 void QFutureWatcherBase::setPendingResultsLimit(int limit)
350 {
351     Q_D(QFutureWatcherBase);
352     d->maximumPendingResultsReady = limit;
353 }
354 
connectNotify(const QMetaMethod & signal)355 void QFutureWatcherBase::connectNotify(const QMetaMethod &signal)
356 {
357     Q_D(QFutureWatcherBase);
358     static const QMetaMethod resultReadyAtSignal = QMetaMethod::fromSignal(&QFutureWatcherBase::resultReadyAt);
359     if (signal == resultReadyAtSignal)
360         d->resultAtConnected.ref();
361 #ifndef QT_NO_DEBUG
362     static const QMetaMethod finishedSignal = QMetaMethod::fromSignal(&QFutureWatcherBase::finished);
363     if (signal == finishedSignal) {
364         if (futureInterface().isRunning()) {
365             //connections should be established before calling stFuture to avoid race.
366             // (The future could finish before the connection is made.)
367             qWarning("QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race");
368         }
369     }
370 #endif
371 }
372 
disconnectNotify(const QMetaMethod & signal)373 void QFutureWatcherBase::disconnectNotify(const QMetaMethod &signal)
374 {
375     Q_D(QFutureWatcherBase);
376     static const QMetaMethod resultReadyAtSignal = QMetaMethod::fromSignal(&QFutureWatcherBase::resultReadyAt);
377     if (signal == resultReadyAtSignal)
378         d->resultAtConnected.deref();
379 }
380 
381 /*!
382     \internal
383 */
QFutureWatcherBasePrivate()384 QFutureWatcherBasePrivate::QFutureWatcherBasePrivate()
385     : maximumPendingResultsReady(QThread::idealThreadCount() * 2),
386       resultAtConnected(0),
387       finished(true) /* the initial m_future is a canceledResult(), with Finished set */
388 { }
389 
390 /*!
391     \internal
392 */
connectOutputInterface()393 void QFutureWatcherBase::connectOutputInterface()
394 {
395     futureInterface().d->connectOutputInterface(d_func());
396 }
397 
398 /*!
399     \internal
400 */
disconnectOutputInterface(bool pendingAssignment)401 void QFutureWatcherBase::disconnectOutputInterface(bool pendingAssignment)
402 {
403     if (pendingAssignment) {
404         Q_D(QFutureWatcherBase);
405         d->pendingResultsReady.storeRelaxed(0);
406         qDeleteAll(d->pendingCallOutEvents);
407         d->pendingCallOutEvents.clear();
408         d->finished = false; /* May soon be amended, during connectOutputInterface() */
409     }
410 
411     futureInterface().d->disconnectOutputInterface(d_func());
412 }
413 
postCallOutEvent(const QFutureCallOutEvent & callOutEvent)414 void QFutureWatcherBasePrivate::postCallOutEvent(const QFutureCallOutEvent &callOutEvent)
415 {
416     Q_Q(QFutureWatcherBase);
417 
418     if (callOutEvent.callOutType == QFutureCallOutEvent::ResultsReady) {
419         if (pendingResultsReady.fetchAndAddRelaxed(1) >= maximumPendingResultsReady)
420             q->futureInterface().d->internal_setThrottled(true);
421     }
422 
423     QCoreApplication::postEvent(q, callOutEvent.clone());
424 }
425 
callOutInterfaceDisconnected()426 void QFutureWatcherBasePrivate::callOutInterfaceDisconnected()
427 {
428     QCoreApplication::removePostedEvents(q_func(), QEvent::FutureCallOut);
429 }
430 
sendCallOutEvent(QFutureCallOutEvent * event)431 void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
432 {
433     Q_Q(QFutureWatcherBase);
434 
435     switch (event->callOutType) {
436         case QFutureCallOutEvent::Started:
437             emit q->started();
438         break;
439         case QFutureCallOutEvent::Finished:
440             finished = true;
441             emit q->finished();
442         break;
443         case QFutureCallOutEvent::Canceled:
444             pendingResultsReady.storeRelaxed(0);
445             emit q->canceled();
446         break;
447         case QFutureCallOutEvent::Paused:
448             if (q->futureInterface().isCanceled())
449                 break;
450             emit q->paused();
451         break;
452         case QFutureCallOutEvent::Resumed:
453             if (q->futureInterface().isCanceled())
454                 break;
455             emit q->resumed();
456         break;
457         case QFutureCallOutEvent::ResultsReady: {
458             if (q->futureInterface().isCanceled())
459                 break;
460 
461             if (pendingResultsReady.fetchAndAddRelaxed(-1) <= maximumPendingResultsReady)
462                 q->futureInterface().setThrottled(false);
463 
464             const int beginIndex = event->index1;
465             const int endIndex = event->index2;
466 
467             emit q->resultsReadyAt(beginIndex, endIndex);
468 
469             if (resultAtConnected.loadRelaxed() <= 0)
470                 break;
471 
472             for (int i = beginIndex; i < endIndex; ++i)
473                 emit q->resultReadyAt(i);
474 
475         } break;
476         case QFutureCallOutEvent::Progress:
477             if (q->futureInterface().isCanceled())
478                 break;
479 
480             emit q->progressValueChanged(event->index1);
481             if (!event->text.isNull()) // ###
482                 emit q->progressTextChanged(event->text);
483         break;
484         case QFutureCallOutEvent::ProgressRange:
485             emit q->progressRangeChanged(event->index1, event->index2);
486         break;
487         default: break;
488     }
489 }
490 
491 
492 /*! \fn template <typename T> const T &QFutureWatcher<T>::result() const
493 
494     Returns the first result in the future(). If the result is not immediately
495     available, this function will block and wait for the result to become
496     available. This is a convenience method for calling resultAt(0).
497 
498     \sa resultAt()
499 */
500 
501 /*! \fn template <typename T> const T &QFutureWatcher<T>::resultAt(int index) const
502 
503     Returns the result at \a index in the future(). If the result is not
504     immediately available, this function will block and wait for the result to
505     become available.
506 
507     \sa result()
508 */
509 
510 /*! \fn template <typename T> void QFutureWatcher<T>::setFuture(const QFuture<T> &future)
511 
512     Starts watching the given \a future.
513 
514     One of the signals might be emitted for the current state of the
515     \a future. For example, if the future is already stopped, the
516     finished signal will be emitted.
517 
518     To avoid a race condition, it is important to call this function
519     \e after doing the connections.
520 */
521 
522 /*! \fn template <typename T> QFuture<T> QFutureWatcher<T>::future() const
523 
524     Returns the watched future.
525 */
526 
527 /*! \fn template <typename T> void QFutureWatcher<T>::started()
528 
529     This signal is emitted when this QFutureWatcher starts watching the future
530     set with setFuture().
531 */
532 
533 /*!
534     \fn template <typename T> void QFutureWatcher<T>::finished()
535     This signal is emitted when the watched future finishes.
536 */
537 
538 /*!
539     \fn template <typename T> void QFutureWatcher<T>::canceled()
540     This signal is emitted if the watched future is canceled.
541 */
542 
543 /*! \fn template <typename T> void QFutureWatcher<T>::paused()
544     This signal is emitted when the watched future is paused.
545 */
546 
547 /*! \fn template <typename T> void QFutureWatcher<T>::resumed()
548     This signal is emitted when the watched future is resumed.
549 */
550 
551 /*!
552     \fn template <typename T> void QFutureWatcher<T>::progressRangeChanged(int minimum, int maximum)
553 
554     The progress range for the watched future has changed to \a minimum and
555     \a maximum
556 */
557 
558 /*!
559     \fn template <typename T> void QFutureWatcher<T>::progressValueChanged(int progressValue)
560 
561     This signal is emitted when the watched future reports progress,
562     \a progressValue gives the current progress. In order to avoid overloading
563     the GUI event loop, QFutureWatcher limits the progress signal emission
564     rate. This means that listeners connected to this slot might not get all
565     progress reports the future makes. The last progress update (where
566     \a progressValue equals the maximum value) will always be delivered.
567 */
568 
569 /*! \fn template <typename T> void QFutureWatcher<T>::progressTextChanged(const QString &progressText)
570 
571     This signal is emitted when the watched future reports textual progress
572     information, \a progressText.
573 */
574 
575 /*!
576     \fn template <typename T> void QFutureWatcher<T>::resultReadyAt(int index)
577 
578     This signal is emitted when the watched future reports a ready result at
579     \a index. If the future reports multiple results, the index will indicate
580     which one it is. Results can be reported out-of-order. To get the result,
581     call resultAt(index);
582 */
583 
584 /*!
585     \fn template <typename T> void QFutureWatcher<T>::resultsReadyAt(int beginIndex, int endIndex);
586 
587     This signal is emitted when the watched future reports ready results.
588     The results are indexed from \a beginIndex to \a endIndex.
589 
590 */
591 
592 QT_END_NAMESPACE
593 
594 #include "moc_qfuturewatcher.cpp"
595