1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtCore module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 #include "qplatformdefs.h"
46 #include <private/qcoreapplication_p.h>
47 #if !defined(QT_NO_GLIB)
48 # include "../kernel/qeventdispatcher_glib_p.h"
51 #include <private/qeventdispatcher_unix_p.h>
53 #include "qthreadstorage.h"
55 #include "qthread_p.h"
63 #include <sys/sysctl.h>
66 # if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
67 # include <vxCpuLib.h>
69 # define QT_VXWORKS_HAS_CPUSET
74 #include <sys/pstat.h>
79 # define old_qDebug qDebug
82 #ifndef QT_NO_CORESERVICES
83 # include <CoreServices/CoreServices.h>
84 #endif //QT_NO_CORESERVICES
88 # define qDebug QT_NO_QDEBUG_MACRO
93 #if defined(Q_OS_LINUX)
94 #include <sys/prctl.h>
97 #if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
102 #if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
103 #define QT_HAS_THREAD_PRIORITY_SCHEDULING
111 enum { ThreadPriorityResetFlag = 0x80000000 };
113 #if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL))
116 #if defined(Q_CC_XLC) || defined (Q_CC_SUN)
121 static __thread QThreadData *currentThreadData = 0;
124 static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
125 static pthread_key_t current_thread_data_key;
127 static void destroy_current_thread_data(void *p)
129 #if defined(Q_OS_VXWORKS)
130 // Calling setspecific(..., 0) sets the value to 0 for ALL threads.
131 // The 'set to 1' workaround adds a bit of an overhead though,
132 // since this function is called twice now.
136 // POSIX says the value in our key is set to zero before calling
137 // this destructor function, so we need to set it back to the
139 pthread_setspecific(current_thread_data_key, p);
140 QThreadData *data = static_cast<QThreadData *>(p);
141 if (data->isAdopted) {
142 QThread *thread = data->thread;
144 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
145 Q_ASSERT(!thread_p->finished);
146 thread_p->finish(thread);
150 // ... but we must reset it to zero before returning so we aren't
151 // called again (POSIX allows implementations to call destructor
152 // functions repeatedly until all values are zero)
153 pthread_setspecific(current_thread_data_key,
154 #if defined(Q_OS_VXWORKS)
161 static void create_current_thread_data_key()
163 pthread_key_create(¤t_thread_data_key, destroy_current_thread_data);
166 static void destroy_current_thread_data_key()
168 pthread_once(¤t_thread_data_once, create_current_thread_data_key);
169 pthread_key_delete(current_thread_data_key);
171 Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
174 // Utility functions for getting, setting and clearing thread specific data.
175 static QThreadData *get_thread_data()
178 return currentThreadData;
180 pthread_once(¤t_thread_data_once, create_current_thread_data_key);
181 return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
185 static void set_thread_data(QThreadData *data)
188 currentThreadData = data;
190 pthread_once(¤t_thread_data_once, create_current_thread_data_key);
191 pthread_setspecific(current_thread_data_key, data);
194 static void clear_thread_data()
197 currentThreadData = 0;
199 pthread_setspecific(current_thread_data_key, 0);
202 QThreadData *QThreadData::current()
204 QThreadData *data = get_thread_data();
206 data = new QThreadData;
208 set_thread_data(data);
209 data->thread = new QAdoptedThread(data);
217 data->isAdopted = true;
218 data->threadId = (Qt::HANDLE)pthread_self();
219 if (!QCoreApplicationPrivate::theMainThread)
220 QCoreApplicationPrivate::theMainThread = data->thread;
226 void QAdoptedThread::init()
229 d->thread_id = pthread_self();
236 #if defined(Q_C_CALLBACKS)
240 typedef void*(*QtThreadCallback)(void*);
242 #if defined(Q_C_CALLBACKS)
246 #endif // QT_NO_THREAD
248 void QThreadPrivate::createEventDispatcher(QThreadData *data)
250 #if !defined(QT_NO_GLIB)
251 if (qgetenv("QT_NO_GLIB").isEmpty()
252 && qgetenv("QT_NO_THREADED_GLIB").isEmpty()
253 && QEventDispatcherGlib::versionSupported())
254 data->eventDispatcher = new QEventDispatcherGlib;
257 data->eventDispatcher = new QEventDispatcherUNIX;
258 data->eventDispatcher->startingUp();
263 void *QThreadPrivate::start(void *arg)
265 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
266 pthread_cleanup_push(QThreadPrivate::finish, arg);
268 QThread *thr = reinterpret_cast<QThread *>(arg);
269 QThreadData *data = QThreadData::get2(thr);
271 // do we need to reset the thread priority?
272 if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
273 thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
276 data->threadId = (Qt::HANDLE)pthread_self();
277 set_thread_data(data);
281 QMutexLocker locker(&thr->d_func()->mutex);
282 data->quitNow = thr->d_func()->exited;
285 if (data->eventDispatcher) // custom event dispatcher set?
286 data->eventDispatcher->startingUp();
288 createEventDispatcher(data);
290 #if !defined(QT_NO_DEBUG) && (defined(Q_OS_LINUX) || defined(Q_OS_MAC))
291 // sets the name of the current thread.
292 QByteArray objectName = thr->objectName().toLocal8Bit();
294 if (objectName.isEmpty())
295 objectName = thr->metaObject()->className();
297 #if defined(Q_OS_LINUX)
298 prctl(PR_SET_NAME, (unsigned long)objectName.constData(), 0, 0, 0);
299 #elif defined(Q_OS_MAC)
300 pthread_setname_np(objectName.constData());
305 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
306 pthread_testcancel();
309 pthread_cleanup_pop(1);
314 void QThreadPrivate::finish(void *arg)
316 QThread *thr = reinterpret_cast<QThread *>(arg);
317 QThreadPrivate *d = thr->d_func();
319 QMutexLocker locker(&d->mutex);
321 d->isInFinish = true;
322 d->priority = QThread::InheritPriority;
323 bool terminated = d->terminated;
324 void *data = &d->data->tls;
327 emit thr->terminated();
328 emit thr->finished();
329 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
330 QThreadStorageData::finish((void **)data);
332 d->terminated = false;
334 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher;
335 if (eventDispatcher) {
336 d->data->eventDispatcher = 0;
338 eventDispatcher->closingDown();
339 delete eventDispatcher;
347 d->isInFinish = false;
348 d->thread_done.wakeAll();
354 /**************************************************************************
356 *************************************************************************/
358 Qt::HANDLE QThread::currentThreadId()
360 // requires a C cast here otherwise we run into trouble on AIX
361 return (Qt::HANDLE)pthread_self();
364 #if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
365 // LSB doesn't define _SC_NPROCESSORS_ONLN.
366 # define _SC_NPROCESSORS_ONLN 84
369 int QThread::idealThreadCount()
373 #if defined(Q_OS_MAC) && !defined(QT_NO_CORESERVICES)
375 cores = MPProcessorsScheduled();
376 #elif defined(Q_OS_HPUX)
378 struct pst_dynamic psd;
379 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
380 perror("pstat_getdynamic");
383 cores = (int)psd.psd_proc_cnt;
385 #elif defined(Q_OS_BSD4)
386 // FreeBSD, OpenBSD, NetBSD, BSD/OS
387 size_t len = sizeof(cores);
391 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
395 #elif defined(Q_OS_IRIX)
397 cores = (int)sysconf(_SC_NPROC_ONLN);
398 #elif defined(Q_OS_INTEGRITY)
399 // as of aug 2008 Integrity only supports one single core CPU
401 #elif defined(Q_OS_VXWORKS)
403 # if defined(QT_VXWORKS_HAS_CPUSET)
404 cpuset_t cpus = vxCpuEnabledGet();
407 // 128 cores should be enough for everyone ;)
408 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
409 if (CPUSET_ISSET(cpus, i)) {
415 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
419 // the rest: Linux, Solaris, AIX, Tru64
420 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
426 void QThread::yieldCurrentThread()
432 helper function to do thread sleeps, since usleep()/nanosleep()
433 aren't reliable enough (in terms of behavior and availability)
435 static void thread_sleep(struct timespec *ti)
440 pthread_mutex_init(&mtx, 0);
441 pthread_cond_init(&cnd, 0);
443 pthread_mutex_lock(&mtx);
444 (void) pthread_cond_timedwait(&cnd, &mtx, ti);
445 pthread_mutex_unlock(&mtx);
447 pthread_cond_destroy(&cnd);
448 pthread_mutex_destroy(&mtx);
451 void QThread::sleep(unsigned long secs)
454 gettimeofday(&tv, 0);
456 ti.tv_sec = tv.tv_sec + secs;
457 ti.tv_nsec = (tv.tv_usec * 1000);
461 void QThread::msleep(unsigned long msecs)
464 gettimeofday(&tv, 0);
467 ti.tv_nsec = (tv.tv_usec + (msecs % 1000) * 1000) * 1000;
468 ti.tv_sec = tv.tv_sec + (msecs / 1000) + (ti.tv_nsec / 1000000000);
469 ti.tv_nsec %= 1000000000;
473 void QThread::usleep(unsigned long usecs)
476 gettimeofday(&tv, 0);
479 ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
480 ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
481 ti.tv_nsec %= 1000000000;
485 #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
486 // Does some magic and calculate the Unix scheduler priorities
487 // sched_policy is IN/OUT: it must be set to a valid policy before calling this function
488 // sched_priority is OUT only
489 static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
492 if (priority == QThread::IdlePriority) {
493 *sched_policy = SCHED_IDLE;
497 const int lowestPriority = QThread::LowestPriority;
499 const int lowestPriority = QThread::IdlePriority;
501 const int highestPriority = QThread::TimeCriticalPriority;
503 int prio_min = sched_get_priority_min(*sched_policy);
504 int prio_max = sched_get_priority_max(*sched_policy);
505 if (prio_min == -1 || prio_max == -1)
509 // crudely scale our priority enum values to the prio_min/prio_max
510 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
511 prio = qMax(prio_min, qMin(prio_max, prio));
513 *sched_priority = prio;
518 void QThread::start(Priority priority)
521 QMutexLocker locker(&d->mutex);
524 d->thread_done.wait(locker.mutex());
531 d->terminated = false;
536 pthread_attr_init(&attr);
537 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
539 d->priority = priority;
541 #if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
543 case InheritPriority:
545 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
552 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
553 // failed to get the scheduling policy, don't bother
554 // setting the priority
555 qWarning("QThread::start: Cannot determine default scheduler policy");
560 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
561 // failed to get the scheduling parameters, don't
562 // bother setting the priority
563 qWarning("QThread::start: Cannot determine scheduler priority range");
568 sp.sched_priority = prio;
570 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
571 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
572 || pthread_attr_setschedparam(&attr, &sp) != 0) {
573 // could not set scheduling hints, fallback to inheriting them
574 // we'll try again from inside the thread
575 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
576 d->priority = Priority(priority | ThreadPriorityResetFlag);
581 #endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
584 if (d->stackSize > 0) {
585 #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
586 int code = pthread_attr_setstacksize(&attr, d->stackSize);
588 int code = ENOSYS; // stack size not supported, automatically fail
589 #endif // _POSIX_THREAD_ATTR_STACKSIZE
592 qWarning("QThread::start: Thread stack size error: %s",
593 qPrintable(qt_error_string(code)));
595 // we failed to set the stacksize, and as the documentation states,
596 // the thread will fail to run...
604 pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
606 // caller does not have permission to set the scheduling
608 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
610 pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
613 pthread_attr_destroy(&attr);
616 qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));
624 void QThread::terminate()
627 QMutexLocker locker(&d->mutex);
632 int code = pthread_cancel(d->thread_id);
634 qWarning("QThread::start: Thread termination error: %s",
635 qPrintable(qt_error_string((code))));
637 d->terminated = true;
641 bool QThread::wait(unsigned long time)
644 QMutexLocker locker(&d->mutex);
646 if (d->thread_id == pthread_self()) {
647 qWarning("QThread::wait: Thread tried to wait on itself");
651 if (d->finished || !d->running)
655 if (!d->thread_done.wait(locker.mutex(), time))
661 void QThread::setTerminationEnabled(bool enabled)
663 QThread *thr = currentThread();
664 Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
665 "Current thread was not started with QThread.");
668 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
670 pthread_testcancel();
673 void QThread::setPriority(Priority priority)
676 QMutexLocker locker(&d->mutex);
678 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
682 d->priority = priority;
684 // copied from start() with a few modifications:
686 #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
690 if (pthread_getschedparam(d->thread_id, &sched_policy, ¶m) != 0) {
691 // failed to get the scheduling policy, don't bother setting
693 qWarning("QThread::setPriority: Cannot get scheduler parameters");
698 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
699 // failed to get the scheduling parameters, don't
700 // bother setting the priority
701 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
705 param.sched_priority = prio;
706 int status = pthread_setschedparam(d->thread_id, sched_policy, ¶m);
709 // were we trying to set to idle priority and failed?
710 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
711 // reset to lowest priority possible
712 pthread_getschedparam(d->thread_id, &sched_policy, ¶m);
713 param.sched_priority = sched_get_priority_min(sched_policy);
714 pthread_setschedparam(d->thread_id, sched_policy, ¶m);
718 # endif // SCHED_IDLE
722 #endif // QT_NO_THREAD