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

« back to all changes in this revision

Viewing changes to src/corelib/thread/qthread_unix.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
 
 
31
#include "qplatformdefs.h"
 
32
 
 
33
#include <private/qeventdispatcher_unix_p.h>
 
34
#include "qthreadstorage.h"
 
35
 
 
36
#include "qthread_p.h"
 
37
 
 
38
#include <sched.h>
 
39
#include <errno.h>
 
40
#include <string.h>
 
41
 
 
42
 
 
43
/*
 
44
   QThreadPrivate
 
45
*/
 
46
 
 
47
#if defined(Q_C_CALLBACKS)
 
48
extern "C" {
 
49
#endif
 
50
 
 
51
typedef void*(*QtThreadCallback)(void*);
 
52
 
 
53
#if defined(Q_C_CALLBACKS)
 
54
}
 
55
#endif
 
56
 
 
57
static pthread_once_t current_thread_key_once = PTHREAD_ONCE_INIT;
 
58
static pthread_key_t current_thread_key;
 
59
static void create_current_thread_key()
 
60
{ pthread_key_create(&current_thread_key, NULL); }
 
61
 
 
62
void QThreadPrivate::setCurrentThread(QThread *thread)
 
63
{
 
64
    pthread_once(&current_thread_key_once, create_current_thread_key);
 
65
    pthread_setspecific(current_thread_key, thread);
 
66
}
 
67
 
 
68
void *QThreadPrivate::start(void *arg)
 
69
{
 
70
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
71
 
 
72
    QThread *thr = reinterpret_cast<QThread *>(arg);
 
73
    setCurrentThread(thr);
 
74
 
 
75
    pthread_cleanup_push(QThreadPrivate::finish, arg);
 
76
 
 
77
    QThreadData *data = QThreadData::get(thr);
 
78
    data->quitNow = false;
 
79
    // ### TODO: allow the user to create a custom event dispatcher
 
80
    data->eventDispatcher = new QEventDispatcherUNIX;
 
81
    data->eventDispatcher->startingUp();
 
82
 
 
83
    emit thr->started();
 
84
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 
85
    pthread_testcancel();
 
86
    thr->run();
 
87
 
 
88
    pthread_cleanup_pop(1);
 
89
    return 0;
 
90
}
 
91
 
 
92
void QThreadPrivate::finish(void *arg)
 
93
{
 
94
    QThread *thr = reinterpret_cast<QThread *>(arg);
 
95
    QThreadPrivate *d = thr->d_func();
 
96
    QThreadData *data = &d->data;
 
97
    QMutexLocker locker(&d->mutex);
 
98
 
 
99
    d->running = false;
 
100
    d->finished = true;
 
101
    if (d->terminated)
 
102
        emit thr->terminated();
 
103
    d->terminated = false;
 
104
    emit thr->finished();
 
105
 
 
106
    data->eventDispatcher->closingDown();
 
107
    QAbstractEventDispatcher *eventDispatcher = data->eventDispatcher;
 
108
    data->eventDispatcher = 0;
 
109
    delete eventDispatcher;
 
110
 
 
111
    QThreadStorageData::finish(data->tls);
 
112
    data->tls = 0;
 
113
 
 
114
    d->thread_id = 0;
 
115
    d->thread_done.wakeAll();
 
116
}
 
117
 
 
118
 
 
119
 
 
120
 
 
121
/**************************************************************************
 
122
 ** QThread
 
123
 *************************************************************************/
 
124
 
 
125
/*!
 
126
    Returns the thread handle of the currently executing thread.
 
127
 
 
128
    \warning The handle returned by this function is used for internal
 
129
    purposes and should not be used in any application code. On
 
130
    Windows, the returned value is a pseudo-handle for the current
 
131
    thread that cannot be used for numerical comparison.
 
132
*/
 
133
Qt::HANDLE QThread::currentThreadId()
 
134
{
 
135
    // requires a C cast here otherwise we run into trouble on AIX
 
136
    return (Qt::HANDLE)pthread_self();
 
137
}
 
138
 
 
139
/*!
 
140
    Returns a pointer to the currently executing QThread. If the
 
141
    current thread was not started using the QThread API (e.g., the
 
142
    GUI thread), this function returns zero.
 
143
*/
 
144
QThread *QThread::currentThread()
 
145
{
 
146
    pthread_once(&current_thread_key_once, create_current_thread_key);
 
147
    return reinterpret_cast<QThread *>(pthread_getspecific(current_thread_key));
 
148
}
 
149
 
 
150
/*  \internal
 
151
    helper function to do thread sleeps, since usleep()/nanosleep()
 
152
    aren't reliable enough (in terms of behavior and availability)
 
153
*/
 
154
static void thread_sleep(struct timespec *ti)
 
155
{
 
156
    pthread_mutex_t mtx;
 
157
    pthread_cond_t cnd;
 
158
 
 
159
    pthread_mutex_init(&mtx, 0);
 
160
    pthread_cond_init(&cnd, 0);
 
161
 
 
162
    pthread_mutex_lock(&mtx);
 
163
    (void) pthread_cond_timedwait(&cnd, &mtx, ti);
 
164
    pthread_mutex_unlock(&mtx);
 
165
 
 
166
    pthread_cond_destroy(&cnd);
 
167
    pthread_mutex_destroy(&mtx);
 
168
}
 
169
 
 
170
/*!
 
171
    Forces the current thread to sleep for \a secs seconds.
 
172
 
 
173
    \sa msleep(), usleep()
 
174
*/
 
175
void QThread::sleep(unsigned long secs)
 
176
{
 
177
    struct timeval tv;
 
178
    gettimeofday(&tv, 0);
 
179
    struct timespec ti;
 
180
    ti.tv_sec = tv.tv_sec + secs;
 
181
    ti.tv_nsec = (tv.tv_usec * 1000);
 
182
    thread_sleep(&ti);
 
183
}
 
184
 
 
185
/*!
 
186
    Causes the current thread to sleep for \a msecs milliseconds.
 
187
 
 
188
    \sa sleep(), usleep()
 
189
*/
 
190
void QThread::msleep(unsigned long msecs)
 
191
{
 
192
    struct timeval tv;
 
193
    gettimeofday(&tv, 0);
 
194
    struct timespec ti;
 
195
 
 
196
    ti.tv_nsec = (tv.tv_usec + (msecs % 1000) * 1000) * 1000;
 
197
    ti.tv_sec = tv.tv_sec + (msecs / 1000) + (ti.tv_nsec / 1000000000);
 
198
    ti.tv_nsec %= 1000000000;
 
199
    thread_sleep(&ti);
 
200
}
 
201
 
 
202
/*!
 
203
    Causes the current thread to sleep for \a usecs microseconds.
 
204
 
 
205
    \sa sleep(), msleep()
 
206
*/
 
207
void QThread::usleep(unsigned long usecs)
 
208
{
 
209
    struct timeval tv;
 
210
    gettimeofday(&tv, 0);
 
211
    struct timespec ti;
 
212
 
 
213
    ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
 
214
    ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
 
215
    ti.tv_nsec %= 1000000000;
 
216
    thread_sleep(&ti);
 
217
}
 
218
 
 
219
/*!
 
220
    Begins execution of the thread by calling run(), which should be
 
221
    reimplemented in a QThread subclass to contain your code. The
 
222
    operating system will schedule the thread according to the \a
 
223
    priority parameter. If the thread is already running, this
 
224
    function does nothing.
 
225
 
 
226
    \sa run(), terminate()
 
227
*/
 
228
void QThread::start(Priority priority)
 
229
{
 
230
    Q_D(QThread);
 
231
    QMutexLocker locker(&d->mutex);
 
232
    if (d->running)
 
233
        return;
 
234
 
 
235
    d->running = true;
 
236
    d->finished = false;
 
237
    d->terminated = false;
 
238
 
 
239
    pthread_attr_t attr;
 
240
    pthread_attr_init(&attr);
 
241
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
242
 
 
243
#if !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
 
244
    switch (priority) {
 
245
    case InheritPriority:
 
246
        {
 
247
            pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
 
248
            break;
 
249
        }
 
250
 
 
251
    default:
 
252
        {
 
253
            int sched_policy;
 
254
            if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
 
255
                // failed to get the scheduling policy, don't bother
 
256
                // setting the priority
 
257
                qWarning("QThread: cannot determine default scheduler policy");
 
258
                break;
 
259
            }
 
260
 
 
261
            int prio_min = sched_get_priority_min(sched_policy);
 
262
            int prio_max = sched_get_priority_max(sched_policy);
 
263
            if (prio_min == -1 || prio_max == -1) {
 
264
                // failed to get the scheduling parameters, don't
 
265
                // bother setting the priority
 
266
                qWarning("QThread: cannot determine scheduler priority range");
 
267
                break;
 
268
            }
 
269
 
 
270
            int prio;
 
271
            switch (priority) {
 
272
            case IdlePriority:
 
273
                prio = prio_min;
 
274
                break;
 
275
 
 
276
            case HighestPriority:
 
277
                prio = prio_max;
 
278
                break;
 
279
 
 
280
            default:
 
281
                // crudely scale our priority enum values to the prio_min/prio_max
 
282
                prio = (((prio_max - prio_min) / TimeCriticalPriority) * priority) + prio_min;
 
283
                prio = qMax(prio_min, qMin(prio_max, prio));
 
284
                break;
 
285
            }
 
286
 
 
287
            sched_param sp;
 
288
            sp.sched_priority = prio;
 
289
 
 
290
            pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
 
291
            pthread_attr_setschedparam(&attr, &sp);
 
292
            break;
 
293
        }
 
294
    }
 
295
#else
 
296
    Q_UNUSED(priority);
 
297
#endif // _POSIX_THREAD_PRIORITY_SCHEDULING
 
298
 
 
299
    if (d->stackSize > 0) {
 
300
#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
 
301
        int code = pthread_attr_setstacksize(&attr, d->stackSize);
 
302
#else
 
303
        int code = ENOSYS; // stack size not supported, automatically fail
 
304
#endif // _POSIX_THREAD_ATTR_STACKSIZE
 
305
 
 
306
        if (code) {
 
307
            qWarning("QThread::start: thread stack size error: %s", strerror(code)) ;
 
308
 
 
309
            // we failed to set the stacksize, and as the documentation states,
 
310
            // the thread will fail to run...
 
311
            d->running = false;
 
312
            d->finished = false;
 
313
            return;
 
314
        }
 
315
    }
 
316
 
 
317
    int code =
 
318
        pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
 
319
    if (code == EPERM) {
 
320
        // caller does not have permission to set the scheduling
 
321
        // parameters/policy
 
322
        pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
 
323
        code =
 
324
            pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
 
325
    }
 
326
 
 
327
    pthread_attr_destroy(&attr);
 
328
 
 
329
    if (code) {
 
330
        qWarning("QThread::start: thread creation error: %s", strerror(code));
 
331
 
 
332
        d->running = false;
 
333
        d->finished = false;
 
334
        d->thread_id = 0;
 
335
    }
 
336
}
 
337
 
 
338
/*!
 
339
    Terminates the execution of the thread. The thread may or may not
 
340
    be terminated immediately, depending on the operating systems
 
341
    scheduling policies. Use QThread::wait() after terminate() for
 
342
    synchronous termination.
 
343
 
 
344
    When the thread is terminated, all threads waiting for the thread
 
345
    to finish will be woken up.
 
346
 
 
347
    \warning This function is dangerous and its use is discouraged.
 
348
    The thread can be terminate at any point in its code path.
 
349
    Threads can be terminated while modifying data. There is no
 
350
    chance for the thread to cleanup after itself, unlock any held
 
351
    mutexes, etc. In short, use this function only if absolutely
 
352
    necessary.
 
353
 
 
354
    Termination can be explicitly enabled or disabled by calling
 
355
    QThread::setTerminationEnabled(). Calling this function while
 
356
    termination is disabled results in the termination being
 
357
    deferred, until termination is re-enabled. See the documentation
 
358
    of QThread::setTerminationEnabled() for more information.
 
359
 
 
360
    \sa setTerminationEnabled()
 
361
*/
 
362
void QThread::terminate()
 
363
{
 
364
    Q_D(QThread);
 
365
    QMutexLocker locker(&d->mutex);
 
366
 
 
367
    if (!d->thread_id)
 
368
        return;
 
369
 
 
370
    int code = pthread_cancel(d->thread_id);
 
371
    if (code) {
 
372
        qWarning("QThread::start: thread termination error: %s", strerror(code));
 
373
    } else {
 
374
        d->terminated = true;
 
375
    }
 
376
}
 
377
 
 
378
/*!
 
379
    Blocks the thread until either of these conditions is met:
 
380
 
 
381
    \list
 
382
    \o The thread associated with this QThread object has finished
 
383
       execution (i.e. when it returns from \l{run()}). This function
 
384
       will return true if the thread has finished. It also returns
 
385
       true if the thread has not been started yet.
 
386
    \o \a time milliseconds has elapsed. If \a time is ULONG_MAX (the
 
387
        default), then the wait will never timeout (the thread must
 
388
        return from \l{run()}). This function will return false if the
 
389
        wait timed out.
 
390
    \endlist
 
391
 
 
392
    This provides similar functionality to the POSIX \c
 
393
    pthread_join() function.
 
394
 
 
395
    \sa sleep(), terminate()
 
396
*/
 
397
bool QThread::wait(unsigned long time)
 
398
{
 
399
    Q_D(QThread);
 
400
    QMutexLocker locker(&d->mutex);
 
401
 
 
402
    if (d->thread_id == pthread_self()) {
 
403
        qWarning("QThread::wait: thread tried to wait on itself");
 
404
        return false;
 
405
    }
 
406
 
 
407
    if (d->finished || !d->running)
 
408
        return true;
 
409
 
 
410
    while (d->running) {
 
411
        if (!d->thread_done.wait(locker.mutex(), time))
 
412
            return false;
 
413
    }
 
414
    return true;
 
415
}
 
416
 
 
417
/*!
 
418
    Enables or disables termination of the current thread based on the
 
419
    \a enabled parameter. The thread must have been started by
 
420
    QThread.
 
421
 
 
422
    When \a enabled is false, termination is disabled.  Future calls
 
423
    to QThread::terminate() will return immediately without effect.
 
424
    Instead, the termination is deferred until termination is enabled.
 
425
 
 
426
    When \a enabled is true, termination is enabled.  Future calls to
 
427
    QThread::terminate() will terminate the thread normally.  If
 
428
    termination has been deferred (i.e. QThread::terminate() was
 
429
    called with termination disabled), this function will terminate
 
430
    the calling thread \e immediately.  Note that this function will
 
431
    not return in this case.
 
432
 
 
433
    \sa terminate()
 
434
*/
 
435
void QThread::setTerminationEnabled(bool enabled)
 
436
{
 
437
    Q_ASSERT_X(currentThread() != 0, "QThread::setTerminationEnabled()",
 
438
               "Current thread was not started with QThread.");
 
439
    pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
 
440
    if (enabled)
 
441
        pthread_testcancel();
 
442
}