~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/corelib/kernel/qeventloop.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "qeventloop.h"
 
41
 
 
42
#include "qabstracteventdispatcher.h"
 
43
#include "qcoreapplication.h"
 
44
#include "qcoreapplication_p.h"
 
45
#include "qelapsedtimer.h"
 
46
 
 
47
#include "qobject_p.h"
 
48
#include "qeventloop_p.h"
 
49
#include <private/qthread_p.h>
 
50
 
 
51
QT_BEGIN_NAMESPACE
 
52
 
 
53
/*!
 
54
    \class QEventLoop
 
55
    \inmodule QtCore
 
56
    \brief The QEventLoop class provides a means of entering and leaving an event loop.
 
57
 
 
58
    At any time, you can create a QEventLoop object and call exec()
 
59
    on it to start a local event loop. From within the event loop,
 
60
    calling exit() will force exec() to return.
 
61
 
 
62
    \sa QAbstractEventDispatcher
 
63
*/
 
64
 
 
65
/*!
 
66
    \enum QEventLoop::ProcessEventsFlag
 
67
 
 
68
    This enum controls the types of events processed by the
 
69
    processEvents() functions.
 
70
 
 
71
    \value AllEvents All events. Note that
 
72
    \l{QEvent::DeferredDelete}{DeferredDelete} events are processed
 
73
    specially. See QObject::deleteLater() for more details.
 
74
 
 
75
    \value ExcludeUserInputEvents Do not process user input events,
 
76
    such as ButtonPress and KeyPress. Note that the events are not
 
77
    discarded; they will be delivered the next time processEvents() is
 
78
    called without the ExcludeUserInputEvents flag.
 
79
 
 
80
    \value ExcludeSocketNotifiers Do not process socket notifier
 
81
    events. Note that the events are not discarded; they will be
 
82
    delivered the next time processEvents() is called without the
 
83
    ExcludeSocketNotifiers flag.
 
84
 
 
85
    \value WaitForMoreEvents Wait for events if no pending events are
 
86
    available.
 
87
 
 
88
    \omitvalue X11ExcludeTimers
 
89
    \omitvalue EventLoopExec
 
90
    \omitvalue DialogExec
 
91
 
 
92
    \sa processEvents()
 
93
*/
 
94
 
 
95
/*!
 
96
    Constructs an event loop object with the given \a parent.
 
97
*/
 
98
QEventLoop::QEventLoop(QObject *parent)
 
99
    : QObject(*new QEventLoopPrivate, parent)
 
100
{
 
101
    Q_D(QEventLoop);
 
102
    if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) {
 
103
        qWarning("QEventLoop: Cannot be used without QApplication");
 
104
    } else if (!d->threadData->eventDispatcher.load()) {
 
105
        QThreadPrivate::createEventDispatcher(d->threadData);
 
106
    }
 
107
}
 
108
 
 
109
/*!
 
110
    Destroys the event loop object.
 
111
*/
 
112
QEventLoop::~QEventLoop()
 
113
{ }
 
114
 
 
115
 
 
116
/*!
 
117
    Processes pending events that match \a flags until there are no
 
118
    more events to process. Returns \c true if pending events were handled;
 
119
    otherwise returns \c false.
 
120
 
 
121
    This function is especially useful if you have a long running
 
122
    operation and want to show its progress without allowing user
 
123
    input; i.e. by using the \l ExcludeUserInputEvents flag.
 
124
 
 
125
    This function is simply a wrapper for
 
126
    QAbstractEventDispatcher::processEvents(). See the documentation
 
127
    for that function for details.
 
128
*/
 
129
bool QEventLoop::processEvents(ProcessEventsFlags flags)
 
130
{
 
131
    Q_D(QEventLoop);
 
132
    if (!d->threadData->eventDispatcher.load())
 
133
        return false;
 
134
    return d->threadData->eventDispatcher.load()->processEvents(flags);
 
135
}
 
136
 
 
137
/*!
 
138
    Enters the main event loop and waits until exit() is called.
 
139
    Returns the value that was passed to exit().
 
140
 
 
141
    If \a flags are specified, only events of the types allowed by
 
142
    the \a flags will be processed.
 
143
 
 
144
    It is necessary to call this function to start event handling. The
 
145
    main event loop receives events from the window system and
 
146
    dispatches these to the application widgets.
 
147
 
 
148
    Generally speaking, no user interaction can take place before
 
149
    calling exec(). As a special case, modal widgets like QMessageBox
 
150
    can be used before calling exec(), because modal widgets
 
151
    use their own local event loop.
 
152
 
 
153
    To make your application perform idle processing (i.e. executing a
 
154
    special function whenever there are no pending events), use a
 
155
    QTimer with 0 timeout. More sophisticated idle processing schemes
 
156
    can be achieved using processEvents().
 
157
 
 
158
    \sa QCoreApplication::quit(), exit(), processEvents()
 
159
*/
 
160
int QEventLoop::exec(ProcessEventsFlags flags)
 
161
{
 
162
    Q_D(QEventLoop);
 
163
    //we need to protect from race condition with QThread::exit
 
164
    QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
 
165
    if (d->threadData->quitNow)
 
166
        return -1;
 
167
 
 
168
    if (d->inExec) {
 
169
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
 
170
        return -1;
 
171
    }
 
172
 
 
173
    struct LoopReference {
 
174
        QEventLoopPrivate *d;
 
175
        QMutexLocker &locker;
 
176
 
 
177
        bool exceptionCaught;
 
178
        LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
 
179
        {
 
180
            d->inExec = true;
 
181
            d->exit.storeRelease(false);
 
182
            ++d->threadData->loopLevel;
 
183
            d->threadData->eventLoops.push(d->q_func());
 
184
            locker.unlock();
 
185
        }
 
186
 
 
187
        ~LoopReference()
 
188
        {
 
189
            if (exceptionCaught) {
 
190
                qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
 
191
                         "exceptions from an event handler is not supported in Qt.\n"
 
192
                         "You must not let any exception whatsoever propagate through Qt code.\n"
 
193
                         "If that is not possible, in Qt 5 you must at least reimplement\n"
 
194
                         "QCoreApplication::notify() and catch all exceptions there.\n");
 
195
            }
 
196
            locker.relock();
 
197
            QEventLoop *eventLoop = d->threadData->eventLoops.pop();
 
198
            Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
 
199
            Q_UNUSED(eventLoop); // --release warning
 
200
            d->inExec = false;
 
201
            --d->threadData->loopLevel;
 
202
        }
 
203
    };
 
204
    LoopReference ref(d, locker);
 
205
 
 
206
    // remove posted quit events when entering a new event loop
 
207
    QCoreApplication *app = QCoreApplication::instance();
 
208
    if (app && app->thread() == thread())
 
209
        QCoreApplication::removePostedEvents(app, QEvent::Quit);
 
210
 
 
211
    while (!d->exit.loadAcquire())
 
212
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
 
213
 
 
214
    ref.exceptionCaught = false;
 
215
    return d->returnCode.load();
 
216
}
 
217
 
 
218
/*!
 
219
    Process pending events that match \a flags for a maximum of \a
 
220
    maxTime milliseconds, or until there are no more events to
 
221
    process, whichever is shorter.
 
222
    This function is especially useful if you have a long running
 
223
    operation and want to show its progress without allowing user
 
224
    input, i.e. by using the \l ExcludeUserInputEvents flag.
 
225
 
 
226
    \b{Notes:}
 
227
    \list
 
228
    \li This function does not process events continuously; it
 
229
       returns after all available events are processed.
 
230
    \li Specifying the \l WaitForMoreEvents flag makes no sense
 
231
       and will be ignored.
 
232
    \endlist
 
233
*/
 
234
void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
 
235
{
 
236
    Q_D(QEventLoop);
 
237
    if (!d->threadData->eventDispatcher.load())
 
238
        return;
 
239
 
 
240
    QElapsedTimer start;
 
241
    start.start();
 
242
    while (processEvents(flags & ~WaitForMoreEvents)) {
 
243
        if (start.elapsed() > maxTime)
 
244
            break;
 
245
    }
 
246
}
 
247
 
 
248
/*!
 
249
    Tells the event loop to exit with a return code.
 
250
 
 
251
    After this function has been called, the event loop returns from
 
252
    the call to exec(). The exec() function returns \a returnCode.
 
253
 
 
254
    By convention, a \a returnCode of 0 means success, and any non-zero
 
255
    value indicates an error.
 
256
 
 
257
    Note that unlike the C library function of the same name, this
 
258
    function \e does return to the caller -- it is event processing that
 
259
    stops.
 
260
 
 
261
    \sa QCoreApplication::quit(), quit(), exec()
 
262
*/
 
263
void QEventLoop::exit(int returnCode)
 
264
{
 
265
    Q_D(QEventLoop);
 
266
    if (!d->threadData->eventDispatcher.load())
 
267
        return;
 
268
 
 
269
    d->returnCode.store(returnCode);
 
270
    d->exit.storeRelease(true);
 
271
    d->threadData->eventDispatcher.load()->interrupt();
 
272
}
 
273
 
 
274
/*!
 
275
    Returns \c true if the event loop is running; otherwise returns
 
276
    false. The event loop is considered running from the time when
 
277
    exec() is called until exit() is called.
 
278
 
 
279
    \sa exec(), exit()
 
280
 */
 
281
bool QEventLoop::isRunning() const
 
282
{
 
283
    Q_D(const QEventLoop);
 
284
    return !d->exit.loadAcquire();
 
285
}
 
286
 
 
287
/*!
 
288
    Wakes up the event loop.
 
289
 
 
290
    \sa QAbstractEventDispatcher::wakeUp()
 
291
*/
 
292
void QEventLoop::wakeUp()
 
293
{
 
294
    Q_D(QEventLoop);
 
295
    if (!d->threadData->eventDispatcher.load())
 
296
        return;
 
297
    d->threadData->eventDispatcher.load()->wakeUp();
 
298
}
 
299
 
 
300
 
 
301
/*!
 
302
    \reimp
 
303
*/
 
304
bool QEventLoop::event(QEvent *event)
 
305
{
 
306
    if (event->type() == QEvent::Quit) {
 
307
        quit();
 
308
        return true;
 
309
    } else {
 
310
        return QObject::event(event);
 
311
    }
 
312
}
 
313
 
 
314
/*!
 
315
    Tells the event loop to exit normally.
 
316
 
 
317
    Same as exit(0).
 
318
 
 
319
    \sa QCoreApplication::quit(), exit()
 
320
*/
 
321
void QEventLoop::quit()
 
322
{ exit(0); }
 
323
 
 
324
 
 
325
class QEventLoopLockerPrivate
 
326
{
 
327
public:
 
328
    explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
 
329
      : loop(loop), type(EventLoop)
 
330
    {
 
331
        loop->ref();
 
332
    }
 
333
 
 
334
    explicit QEventLoopLockerPrivate(QThreadPrivate *thread)
 
335
      : thread(thread), type(Thread)
 
336
    {
 
337
        thread->ref();
 
338
    }
 
339
 
 
340
    explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
 
341
      : app(app), type(Application)
 
342
    {
 
343
        app->ref();
 
344
    }
 
345
 
 
346
    ~QEventLoopLockerPrivate()
 
347
    {
 
348
        switch (type)
 
349
        {
 
350
        case EventLoop:
 
351
            loop->deref();
 
352
            break;
 
353
        case Thread:
 
354
            thread->deref();
 
355
            break;
 
356
        default:
 
357
            app->deref();
 
358
            break;
 
359
        }
 
360
    }
 
361
 
 
362
private:
 
363
    union {
 
364
        QEventLoopPrivate * loop;
 
365
        QThreadPrivate * thread;
 
366
        QCoreApplicationPrivate * app;
 
367
    };
 
368
    enum Type {
 
369
        EventLoop,
 
370
        Thread,
 
371
        Application
 
372
    };
 
373
    const Type type;
 
374
};
 
375
 
 
376
/*!
 
377
    \class QEventLoopLocker
 
378
    \inmodule QtCore
 
379
    \brief The QEventLoopLocker class provides a means to quit an event loop when it is no longer needed.
 
380
    \since 5.0
 
381
 
 
382
    The QEventLoopLocker operates on particular objects - either a QCoreApplication
 
383
    instance, a QEventLoop instance or a QThread instance.
 
384
 
 
385
    This makes it possible to, for example, run a batch of jobs with an event loop
 
386
    and exit that event loop after the last job is finished. That is accomplished
 
387
    by keeping a QEventLoopLocker with each job instance.
 
388
 
 
389
    The variant which operates on QCoreApplication makes it possible to finish
 
390
    asynchronously running jobs after the last gui window has been closed. This
 
391
    can be useful for example for running a job which uploads data to a network.
 
392
 
 
393
    \sa QEventLoop, QCoreApplication
 
394
*/
 
395
 
 
396
/*!
 
397
    Creates an event locker operating on the QCoreApplication.
 
398
 
 
399
    The application will quit when there are no more QEventLoopLockers operating on it.
 
400
 
 
401
    \sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
 
402
 */
 
403
QEventLoopLocker::QEventLoopLocker()
 
404
  : d_ptr(new QEventLoopLockerPrivate(static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()))))
 
405
{
 
406
 
 
407
}
 
408
 
 
409
/*!
 
410
    Creates an event locker operating on the \a loop.
 
411
 
 
412
    This particular QEventLoop will quit when there are no more QEventLoopLockers operating on it.
 
413
 
 
414
    \sa QEventLoop::quit()
 
415
 */
 
416
QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
 
417
  : d_ptr(new QEventLoopLockerPrivate(static_cast<QEventLoopPrivate*>(QObjectPrivate::get(loop))))
 
418
{
 
419
 
 
420
}
 
421
 
 
422
/*!
 
423
    Creates an event locker operating on the \a thread.
 
424
 
 
425
    This particular QThread will quit when there are no more QEventLoopLockers operating on it.
 
426
 
 
427
    \sa QThread::quit()
 
428
 */
 
429
QEventLoopLocker::QEventLoopLocker(QThread *thread)
 
430
  : d_ptr(new QEventLoopLockerPrivate(static_cast<QThreadPrivate*>(QObjectPrivate::get(thread))))
 
431
{
 
432
 
 
433
}
 
434
 
 
435
/*!
 
436
    Destroys this event loop locker object
 
437
 */
 
438
QEventLoopLocker::~QEventLoopLocker()
 
439
{
 
440
    delete d_ptr;
 
441
}
 
442
 
 
443
QT_END_NAMESPACE