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