~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/corelib/thread/qthread.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the core module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qthread.h"
 
30
#include "qthreadstorage.h"
 
31
#include "qmutex.h"
 
32
#include "qmutexpool_p.h"
 
33
#include "qreadwritelock.h"
 
34
 
 
35
#include <qeventloop.h>
 
36
#include <qhash.h>
 
37
 
 
38
#include "qthread_p.h"
 
39
 
 
40
 
 
41
/*
 
42
  QThreadData
 
43
*/
 
44
 
 
45
QThreadData::QThreadData()
 
46
    : id(-1), quitNow(false), allowDeferredDelete(false), eventDispatcher(0), tls(0)
 
47
{ }
 
48
 
 
49
QThreadData::~QThreadData()
 
50
{
 
51
    for (int i = 0; i < postEventList.size(); ++i) {
 
52
        const QPostEvent &pe = postEventList.at(i);
 
53
        if (pe.event) {
 
54
            --pe.receiver->d_func()->postedEvents;
 
55
#ifdef QT3_SUPPORT
 
56
            if (pe.event->type() == QEvent::ChildInserted)
 
57
                --pe.receiver->d_func()->postedChildInsertedEvents;
 
58
#endif
 
59
            pe.event->posted = false;
 
60
            delete pe.event;
 
61
        }
 
62
    }
 
63
}
 
64
 
 
65
QThreadData *QThreadData::get(QThread *thread)
 
66
{
 
67
    Q_ASSERT_X(thread != 0, "QThread", "internal error");
 
68
    return &thread->d_func()->data;
 
69
}
 
70
 
 
71
 
 
72
 
 
73
/*
 
74
  QThreadPrivate
 
75
*/
 
76
 
 
77
QThreadPrivate::QThreadPrivate()
 
78
    : QObjectPrivate(), running(false), finished(false), terminated(false),
 
79
      stackSize(0)
 
80
{
 
81
#if defined (Q_OS_UNIX)
 
82
    thread_id = 0;
 
83
#elif defined (Q_WS_WIN)
 
84
    handle = 0;
 
85
    id = 0;
 
86
    waiters = 0;
 
87
    terminationEnabled = true;
 
88
    terminatePending = false;
 
89
#endif
 
90
 
 
91
    static QBasicAtomic idCounter = Q_ATOMIC_INIT(1);
 
92
    for (;;) {
 
93
        data.id = idCounter;
 
94
        if (idCounter.testAndSet(data.id, data.id + 1))
 
95
            break;
 
96
    }
 
97
}
 
98
 
 
99
struct QThreadIdHash {
 
100
    QReadWriteLock lock;
 
101
    QHash<int, QThread *> table;
 
102
};
 
103
 
 
104
Q_GLOBAL_STATIC(QThreadIdHash, threadIdHash)
 
105
 
 
106
/*! \internal
 
107
 */
 
108
QThread *QThreadPrivate::threadForId(int id)
 
109
{
 
110
    QThreadIdHash *idHash = threadIdHash();
 
111
    if (!idHash)
 
112
        return 0;
 
113
    QReadLocker locker(&idHash->lock);
 
114
    return idHash->table.value(id);
 
115
}
 
116
 
 
117
/*!
 
118
    \class QThread
 
119
    \brief The QThread class provides platform-independent threads.
 
120
 
 
121
    \ingroup thread
 
122
    \ingroup environment
 
123
    \mainclass
 
124
 
 
125
    A QThread represents a separate thread of control within the
 
126
    program; it shares data with all the other threads within the
 
127
    process but executes independently in the way that a separate
 
128
    program does on a multitasking operating system. Instead of
 
129
    starting in \c main(), QThreads begin executing in run().
 
130
    To create your own threads, subclass QThread and reimplement
 
131
    run(). For example:
 
132
 
 
133
    \code
 
134
        class MyThread : public QThread
 
135
        {
 
136
        public:
 
137
            void run();
 
138
        };
 
139
 
 
140
        void MyThread::run()
 
141
        {
 
142
            QTcpSocket socket;
 
143
            // connect QTcpSocket's signals somewhere meaningful
 
144
            ...
 
145
            socket.connectToHost(hostName, portNumber);
 
146
            exec();
 
147
        }
 
148
    \endcode
 
149
 
 
150
    This will create a QTcpSocket in the thread and then execute the
 
151
    thread's event loop. Use the start() method to begin execution.
 
152
    Execution ends when you return from run(), just as an application
 
153
    does when it leaves main(). QThread will notifiy you via a signal
 
154
    when the thread is started(), finished(), and terminated(), or
 
155
    you can use isFinished() and isRunning() to query the state of
 
156
    the thread. Use wait() to block until the thread has finished
 
157
    execution.
 
158
 
 
159
    Each thread gets its own stack from the operating system. The
 
160
    operating system also determines the default size of the stack.
 
161
    You can use setStackSize() to set a custom stack size.
 
162
 
 
163
    Each QThread can have its own event loop. You can start the event
 
164
    loop by calling exec(); you can stop it by calling exit() or
 
165
    quit(). Having an event loop in a thread makes it possible to
 
166
    connect signals from other threads to slots in this threads,
 
167
    using a mechanism called \l{Qt::QueuedConnection}{queued
 
168
    connections}. It also makes it possible to use classes that
 
169
    require the event loop, such as QTimer and QTcpSocket, in the
 
170
    thread.
 
171
 
 
172
    In extreme cases, you may want to forcibly terminate() an
 
173
    executing thread. However, doing so is dangerous and discouraged.
 
174
    Please read the documentation for terminate() and
 
175
    setTerminationEnabled() for detailed information.
 
176
 
 
177
    The static functions currentThreadId() and currentThread() return
 
178
    identifiers for the currently executing thread. The former
 
179
    returns a platform specific ID for the thread; the latter returns
 
180
    a QThread pointer.
 
181
 
 
182
    QThread also provides platform independent sleep functions in
 
183
    varying resolutions. Use sleep() for full second resolution,
 
184
    msleep() for millisecond resolution, and usleep() for microsecond
 
185
    resolution.
 
186
 
 
187
    \sa {threads.html}{Thread Support in Qt}, QThreadStorage, QMutex, QSemaphore, QWaitCondition
 
188
*/
 
189
 
 
190
/*!
 
191
    \fn void QThread::started()
 
192
 
 
193
    This signal is emitted when the thread starts executing.
 
194
 
 
195
    \sa finished(), terminated()
 
196
*/
 
197
 
 
198
/*!
 
199
    \fn void QThread::finished()
 
200
 
 
201
    This signal is emitted when the thread has finished executing.
 
202
 
 
203
    \sa started(), terminated()
 
204
*/
 
205
 
 
206
/*!
 
207
    \fn void QThread::terminated()
 
208
 
 
209
    This signal is emitted when the thread is terminated.
 
210
 
 
211
    \sa started(), finished()
 
212
*/
 
213
 
 
214
/*!
 
215
    \enum QThread::Priority
 
216
 
 
217
    This enum type indicates how the operating system should schedule
 
218
    newly created threads.
 
219
 
 
220
    \value IdlePriority scheduled only when no other threads are
 
221
           running.
 
222
 
 
223
    \value LowestPriority scheduled less often than LowPriority.
 
224
    \value LowPriority scheduled less often than NormalPriority.
 
225
 
 
226
    \value NormalPriority the default priority of the operating
 
227
           system.
 
228
 
 
229
    \value HighPriority scheduled more often than NormalPriority.
 
230
    \value HighestPriority scheduled more often than HighPriority.
 
231
 
 
232
    \value TimeCriticalPriority scheduled as often as possible.
 
233
 
 
234
    \value InheritPriority use the same priority as the creating
 
235
           thread. This is the default.
 
236
*/
 
237
 
 
238
/*!
 
239
    Constructs a new thread with the given \a parent. The thread does
 
240
    not begin executing until start() is called.
 
241
 
 
242
    \sa start()
 
243
*/
 
244
QThread::QThread(QObject *parent)
 
245
    : QObject(*(new QThreadPrivate), parent)
 
246
{
 
247
    Q_D(QThread);
 
248
    QThreadIdHash *idHash = threadIdHash();
 
249
    QWriteLocker locker(&idHash->lock);
 
250
    idHash->table.insert(d->data.id, this);
 
251
}
 
252
 
 
253
/*!
 
254
    Destroys the thread.
 
255
 
 
256
    Note that deleting a QThread object will not stop the execution
 
257
    of the thread it represents. Deleting a running QThread (i.e.
 
258
    isFinished() returns false) will probably result in a program
 
259
    crash. You can wait() on a thread to make sure that it has
 
260
    finished.
 
261
*/
 
262
QThread::~QThread()
 
263
{
 
264
    Q_D(QThread);
 
265
    {
 
266
        QMutexLocker locker(&d->mutex);
 
267
        if (d->running && !d->finished)
 
268
            qWarning("QThread object destroyed while thread is still running.");
 
269
    }
 
270
 
 
271
    QThreadIdHash *idHash = threadIdHash();
 
272
    if (idHash) {
 
273
        QWriteLocker locker(&idHash->lock);
 
274
        idHash->table.remove(d->data.id);
 
275
    }
 
276
}
 
277
 
 
278
/*!
 
279
    Returns true is the thread is finished; otherwise returns false.
 
280
 
 
281
    \sa isRunning()
 
282
*/
 
283
bool QThread::isFinished() const
 
284
{
 
285
    Q_D(const QThread);
 
286
    QMutexLocker locker(&d->mutex);
 
287
    return d->finished;
 
288
}
 
289
 
 
290
/*!
 
291
    Returns true if the thread is running; otherwise returns false.
 
292
 
 
293
    \sa isFinished()
 
294
*/
 
295
bool QThread::isRunning() const
 
296
{
 
297
    Q_D(const QThread);
 
298
    QMutexLocker locker(&d->mutex);
 
299
    return d->running;
 
300
}
 
301
 
 
302
/*!
 
303
    Sets the maximum stack size for the thread to \a stackSize. If \a
 
304
    stackSize is greater than zero, the maximum stack size is set to
 
305
    \a stackSize bytes, otherwise the maximum stack size is
 
306
    automatically determined by the operating system.
 
307
 
 
308
    \warning Most operating systems place minimum and maximum limits
 
309
    on thread stack sizes. The thread will fail to start if the stack
 
310
    size is outside these limits.
 
311
 
 
312
    \sa stackSize()
 
313
*/
 
314
void QThread::setStackSize(uint stackSize)
 
315
{
 
316
    Q_D(QThread);
 
317
    QMutexLocker locker(&d->mutex);
 
318
    Q_ASSERT_X(!d->running, "QThread::setStackSize",
 
319
               "cannot change stack size while the thread is running");
 
320
    d->stackSize = stackSize;
 
321
}
 
322
 
 
323
/*!
 
324
    Returns the maximum stack size for the thread (if set with
 
325
    setStackSize()); otherwise returns zero.
 
326
 
 
327
    \sa setStackSize()
 
328
*/
 
329
uint QThread::stackSize() const
 
330
{
 
331
    Q_D(const QThread);
 
332
    QMutexLocker locker(&d->mutex);
 
333
    return d->stackSize;
 
334
}
 
335
 
 
336
/*!
 
337
    Enters the event loop and waits until exit() is called or the main
 
338
    widget is destroyed, and returns the value that was set to exit()
 
339
    (which is 0 if exit() is called via quit()).
 
340
 
 
341
    It is necessary to call this function to start event handling.
 
342
 
 
343
    \sa quit(), exit()
 
344
*/
 
345
int QThread::exec()
 
346
{
 
347
    Q_D(QThread);
 
348
    d->mutex.lock();
 
349
    QEventLoop eventLoop;
 
350
    d->mutex.unlock();
 
351
    int returnCode = eventLoop.exec();
 
352
    return returnCode;
 
353
}
 
354
 
 
355
/*!
 
356
    Tells the thread's event loop to exit with a return code.
 
357
 
 
358
    After calling this function, the thread leaves the event loop and
 
359
    returns from the call to QEventLoop::exec(). The
 
360
    QEventLoop::exec() function returns \a returnCode.
 
361
 
 
362
    By convention, a \a returnCode of 0 means success, any non-zero value
 
363
    indicates an error.
 
364
 
 
365
    Note that unlike the C library function of the same name, this
 
366
    function \e does return to the caller -- it is event processing
 
367
    that stops.
 
368
 
 
369
    This function does nothing if the thread does not have an event
 
370
    loop.
 
371
 
 
372
    \sa quit() QEventLoop
 
373
*/
 
374
void QThread::exit(int returnCode)
 
375
{
 
376
    Q_D(QThread);
 
377
    QMutexLocker locker(&d->mutex);
 
378
    d->data.quitNow = true;
 
379
    for (int i = 0; i < d->data.eventLoops.size(); ++i) {
 
380
        QEventLoop *eventLoop = d->data.eventLoops.at(i);
 
381
        eventLoop->exit(returnCode);
 
382
    }
 
383
}
 
384
 
 
385
/*!
 
386
    Tells the thread's event loop to exit with return code 0 (success).
 
387
    Equivalent to calling QThread::exit(0).
 
388
 
 
389
    This function does nothing if the thread does not have an event
 
390
    loop.
 
391
 
 
392
    \sa exit() QEventLoop
 
393
*/
 
394
void QThread::quit()
 
395
{ exit(); }
 
396
 
 
397
/*!
 
398
    \fn void QThread::run()
 
399
 
 
400
    This method is pure virtual and must be implemented in derived
 
401
    classes in order to do useful work. Returning from this method
 
402
    will end the execution of the thread.
 
403
 
 
404
    \sa wait()
 
405
*/
 
406
 
 
407
 
 
408
/*! \internal
 
409
    Initializes the QThread system.
 
410
*/
 
411
void QThread::initialize()
 
412
{
 
413
    if (qt_global_mutexpool)
 
414
        return;
 
415
    qt_global_mutexpool = new QMutexPool(true);
 
416
 
 
417
#if defined (Q_OS_WIN)
 
418
    extern void qt_create_tls();
 
419
    qt_create_tls();
 
420
#endif
 
421
}
 
422
 
 
423
 
 
424
/*! \internal
 
425
    Cleans up the QThread system.
 
426
*/
 
427
void QThread::cleanup()
 
428
{
 
429
    delete qt_global_mutexpool;
 
430
    qt_global_mutexpool = 0;
 
431
}
 
432
 
 
433
/*!
 
434
    \fn bool QThread::finished() const
 
435
 
 
436
    Use isFinished() instead.
 
437
*/
 
438
 
 
439
/*!
 
440
    \fn bool QThread::running() const
 
441
 
 
442
    Use isRunning() instead.
 
443
*/