1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtCore module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
44 #include "qplatformdefs.h"
46 #include <private/qcoreapplication_p.h>
47 #if !defined(QT_NO_GLIB)
48 # include "../kernel/qeventdispatcher_glib_p.h"
52 #include <private/qeventdispatcher_symbian_p.h>
54 #include <private/qeventdispatcher_unix_p.h>
57 #include "qthreadstorage.h"
59 #include "qthread_p.h"
67 #include <sys/sysctl.h>
70 # if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
71 # include <vxCpuLib.h>
73 # define QT_VXWORKS_HAS_CPUSET
79 # define old_qDebug qDebug
82 # include <CoreServices/CoreServices.h>
86 # define qDebug QT_NO_QDEBUG_MACRO
95 static pthread_once_t current_thread_data_once
= PTHREAD_ONCE_INIT
;
96 static pthread_key_t current_thread_data_key
;
98 static void destroy_current_thread_data(void *p
)
100 #if defined(Q_OS_VXWORKS)
101 // Calling setspecific(..., 0) sets the value to 0 for ALL threads.
102 // The 'set to 1' workaround adds a bit of an overhead though,
103 // since this function is called twice now.
107 // POSIX says the value in our key is set to zero before calling
108 // this destructor function, so we need to set it back to the
110 pthread_setspecific(current_thread_data_key
, p
);
111 reinterpret_cast<QThreadData
*>(p
)->deref();
112 // ... but we must reset it to zero before returning so we aren't
113 // called again (POSIX allows implementations to call destructor
114 // functions repeatedly until all values are zero)
115 pthread_setspecific(current_thread_data_key
,
116 #if defined(Q_OS_VXWORKS)
123 static void create_current_thread_data_key()
125 pthread_key_create(¤t_thread_data_key
, destroy_current_thread_data
);
128 QThreadData
*QThreadData::current()
130 pthread_once(¤t_thread_data_once
, create_current_thread_data_key
);
132 QThreadData
*data
= reinterpret_cast<QThreadData
*>(pthread_getspecific(current_thread_data_key
));
135 if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread
, &a
)) {
136 QThread
*adopted
= static_cast<QThread
*>(a
);
138 data
= QThreadData::get2(adopted
);
139 pthread_setspecific(current_thread_data_key
, data
);
140 adopted
->d_func()->running
= true;
141 adopted
->d_func()->finished
= false;
142 static_cast<QAdoptedThread
*>(adopted
)->init();
144 data
= new QThreadData
;
145 pthread_setspecific(current_thread_data_key
, data
);
147 data
->thread
= new QAdoptedThread(data
);
149 pthread_setspecific(current_thread_data_key
, 0);
156 if (!QCoreApplicationPrivate::theMainThread
)
157 QCoreApplicationPrivate::theMainThread
= data
->thread
;
163 void QAdoptedThread::init()
166 d
->thread_id
= pthread_self();
168 d
->data
->symbian_thread_handle
= RThread();
169 TThreadId threadId
= d
->data
->symbian_thread_handle
.Id();
170 d
->data
->symbian_thread_handle
.Open(threadId
);
178 #if defined(Q_C_CALLBACKS)
182 typedef void*(*QtThreadCallback
)(void*);
184 #if defined(Q_C_CALLBACKS)
188 #endif // QT_NO_THREAD
190 void QThreadPrivate::createEventDispatcher(QThreadData
*data
)
192 #if !defined(QT_NO_GLIB)
193 if (qgetenv("QT_NO_GLIB").isEmpty()
194 && qgetenv("QT_NO_THREADED_GLIB").isEmpty()
195 && QEventDispatcherGlib::versionSupported())
196 data
->eventDispatcher
= new QEventDispatcherGlib
;
200 data
->eventDispatcher
= new QEventDispatcherSymbian
;
202 data
->eventDispatcher
= new QEventDispatcherUNIX
;
204 data
->eventDispatcher
->startingUp();
209 void *QThreadPrivate::start(void *arg
)
211 // Symbian Open C supports neither thread cancellation nor cleanup_push.
213 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
214 pthread_cleanup_push(QThreadPrivate::finish
, arg
);
217 QThread
*thr
= reinterpret_cast<QThread
*>(arg
);
218 QThreadData
*data
= QThreadData::get2(thr
);
221 // Because Symbian Open C does not provide a way to convert between
222 // RThread and pthread_t, we must delay initialization of the RThread
223 // handle when creating a thread, until we are running in the new thread.
224 // Here, we pick up the current thread and assign that to the handle.
225 data
->symbian_thread_handle
= RThread();
226 TThreadId threadId
= data
->symbian_thread_handle
.Id();
227 data
->symbian_thread_handle
.Open(threadId
);
230 pthread_once(¤t_thread_data_once
, create_current_thread_data_key
);
231 pthread_setspecific(current_thread_data_key
, data
);
234 data
->quitNow
= false;
236 // ### TODO: allow the user to create a custom event dispatcher
237 createEventDispatcher(data
);
241 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
242 pthread_testcancel();
247 QThreadPrivate::finish(arg
);
249 pthread_cleanup_pop(1);
256 void QThreadPrivate::finish(void *arg
, bool lockAnyway
, bool closeNativeHandle
)
258 void QThreadPrivate::finish(void *arg
)
261 QThread
*thr
= reinterpret_cast<QThread
*>(arg
);
262 QThreadPrivate
*d
= thr
->d_func();
268 d
->priority
= QThread::InheritPriority
;
272 emit thr
->terminated();
273 d
->terminated
= false;
274 emit thr
->finished();
276 if (d
->data
->eventDispatcher
) {
277 d
->data
->eventDispatcher
->closingDown();
278 QAbstractEventDispatcher
*eventDispatcher
= d
->data
->eventDispatcher
;
279 d
->data
->eventDispatcher
= 0;
280 delete eventDispatcher
;
283 void *data
= &d
->data
->tls
;
284 QThreadStorageData::finish((void **)data
);
288 if (closeNativeHandle
)
289 d
->data
->symbian_thread_handle
.Close();
291 d
->thread_done
.wakeAll();
301 /**************************************************************************
303 *************************************************************************/
305 Qt::HANDLE
QThread::currentThreadId()
307 // requires a C cast here otherwise we run into trouble on AIX
308 return (Qt::HANDLE
)pthread_self();
311 #if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
312 // LSB doesn't define _SC_NPROCESSORS_ONLN.
313 # define _SC_NPROCESSORS_ONLN 84
316 int QThread::idealThreadCount()
320 #if defined(Q_OS_MAC)
322 cores
= MPProcessorsScheduled();
323 #elif defined(Q_OS_HPUX)
325 struct pst_dynamic psd
;
326 if (pstat_getdynamic(&psd
, sizeof(psd
), 1, 0) == -1) {
327 perror("pstat_getdynamic");
330 cores
= (int)psd
.psd_proc_cnt
;
332 #elif defined(Q_OS_BSD4)
333 // FreeBSD, OpenBSD, NetBSD, BSD/OS
334 size_t len
= sizeof(cores
);
338 if (sysctl(mib
, 2, &cores
, &len
, NULL
, 0) != 0) {
342 #elif defined(Q_OS_IRIX)
344 cores
= (int)sysconf(_SC_NPROC_ONLN
);
345 #elif defined(Q_OS_INTEGRITY)
346 // as of aug 2008 Integrity only supports one single core CPU
348 #elif defined(Q_OS_SYMBIAN)
349 // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported
351 #elif defined(Q_OS_VXWORKS)
353 # if defined(QT_VXWORKS_HAS_CPUSET)
354 cpuset_t cpus
= vxCpuEnabledGet();
357 // 128 cores should be enough for everyone ;)
358 for (int i
= 0; i
< 128 && !CPUSET_ISZERO(cpus
); ++i
) {
359 if (CPUSET_ISSET(cpus
, i
)) {
365 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
369 // the rest: Linux, Solaris, AIX, Tru64
370 cores
= (int)sysconf(_SC_NPROCESSORS_ONLN
);
376 void QThread::yieldCurrentThread()
382 helper function to do thread sleeps, since usleep()/nanosleep()
383 aren't reliable enough (in terms of behavior and availability)
385 static void thread_sleep(struct timespec
*ti
)
390 pthread_mutex_init(&mtx
, 0);
391 pthread_cond_init(&cnd
, 0);
393 pthread_mutex_lock(&mtx
);
394 (void) pthread_cond_timedwait(&cnd
, &mtx
, ti
);
395 pthread_mutex_unlock(&mtx
);
397 pthread_cond_destroy(&cnd
);
398 pthread_mutex_destroy(&mtx
);
401 void QThread::sleep(unsigned long secs
)
404 gettimeofday(&tv
, 0);
406 ti
.tv_sec
= tv
.tv_sec
+ secs
;
407 ti
.tv_nsec
= (tv
.tv_usec
* 1000);
411 void QThread::msleep(unsigned long msecs
)
414 gettimeofday(&tv
, 0);
417 ti
.tv_nsec
= (tv
.tv_usec
+ (msecs
% 1000) * 1000) * 1000;
418 ti
.tv_sec
= tv
.tv_sec
+ (msecs
/ 1000) + (ti
.tv_nsec
/ 1000000000);
419 ti
.tv_nsec
%= 1000000000;
423 void QThread::usleep(unsigned long usecs
)
426 gettimeofday(&tv
, 0);
429 ti
.tv_nsec
= (tv
.tv_usec
+ (usecs
% 1000000)) * 1000;
430 ti
.tv_sec
= tv
.tv_sec
+ (usecs
/ 1000000) + (ti
.tv_nsec
/ 1000000000);
431 ti
.tv_nsec
%= 1000000000;
435 void QThread::start(Priority priority
)
438 QMutexLocker
locker(&d
->mutex
);
444 d
->terminated
= false;
447 pthread_attr_init(&attr
);
448 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
450 d
->priority
= priority
;
452 #if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && !defined(Q_OS_SYMBIAN) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
453 // ### Need to implement thread sheduling and priorities for symbian os. Implementation removed for now
455 case InheritPriority
:
457 pthread_attr_setinheritsched(&attr
, PTHREAD_INHERIT_SCHED
);
464 if (pthread_attr_getschedpolicy(&attr
, &sched_policy
) != 0) {
465 // failed to get the scheduling policy, don't bother
466 // setting the priority
467 qWarning("QThread::start: Cannot determine default scheduler policy");
471 int prio_min
= sched_get_priority_min(sched_policy
);
472 int prio_max
= sched_get_priority_max(sched_policy
);
473 if (prio_min
== -1 || prio_max
== -1) {
474 // failed to get the scheduling parameters, don't
475 // bother setting the priority
476 qWarning("QThread::start: Cannot determine scheduler priority range");
486 case TimeCriticalPriority
:
491 // crudely scale our priority enum values to the prio_min/prio_max
492 prio
= (priority
* (prio_max
- prio_min
) / TimeCriticalPriority
) + prio_min
;
493 prio
= qMax(prio_min
, qMin(prio_max
, prio
));
498 sp
.sched_priority
= prio
;
500 if (pthread_attr_setinheritsched(&attr
, PTHREAD_EXPLICIT_SCHED
) != 0
501 || pthread_attr_setschedpolicy(&attr
, sched_policy
) != 0
502 || pthread_attr_setschedparam(&attr
, &sp
) != 0) {
503 // could not set scheduling hints, fallback to inheriting them
504 pthread_attr_setinheritsched(&attr
, PTHREAD_INHERIT_SCHED
);
509 #endif // _POSIX_THREAD_PRIORITY_SCHEDULING
512 if (d
->stackSize
== 0)
513 // The default stack size on Symbian is very small, making even basic
514 // operations like file I/O fail, so we increase it by default.
515 d
->stackSize
= 0x14000; // Maximum stack size on Symbian.
518 if (d
->stackSize
> 0) {
519 #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
520 int code
= pthread_attr_setstacksize(&attr
, d
->stackSize
);
522 int code
= ENOSYS
; // stack size not supported, automatically fail
523 #endif // _POSIX_THREAD_ATTR_STACKSIZE
526 qWarning("QThread::start: Thread stack size error: %s",
527 qPrintable(qt_error_string(code
)));
529 // we failed to set the stacksize, and as the documentation states,
530 // the thread will fail to run...
538 pthread_create(&d
->thread_id
, &attr
, QThreadPrivate::start
, this);
540 // caller does not have permission to set the scheduling
543 pthread_attr_setinheritsched(&attr
, PTHREAD_INHERIT_SCHED
);
546 pthread_create(&d
->thread_id
, &attr
, QThreadPrivate::start
, this);
549 pthread_attr_destroy(&attr
);
552 qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code
)));
558 d
->data
->symbian_thread_handle
.Close();
563 void QThread::terminate()
566 QMutexLocker
locker(&d
->mutex
);
572 int code
= pthread_cancel(d
->thread_id
);
574 qWarning("QThread::start: Thread termination error: %s",
575 qPrintable(qt_error_string((code
))));
577 d
->terminated
= true;
582 if (!d
->terminationEnabled
) {
583 d
->terminatePending
= true;
587 d
->terminated
= true;
588 // "false, false" meaning:
589 // 1. lockAnyway = false. Don't lock the mutex because it's already locked
591 // 2. closeNativeSymbianHandle = false. We don't want to close the thread handle,
592 // because we need it here to terminate the thread.
593 QThreadPrivate::finish(this, false, false);
594 d
->data
->symbian_thread_handle
.Terminate(KErrNone
);
595 d
->data
->symbian_thread_handle
.Close();
601 bool QThread::wait(unsigned long time
)
604 QMutexLocker
locker(&d
->mutex
);
606 if (d
->thread_id
== pthread_self()) {
607 qWarning("QThread::wait: Thread tried to wait on itself");
611 if (d
->finished
|| !d
->running
)
615 if (!d
->thread_done
.wait(locker
.mutex(), time
))
621 void QThread::setTerminationEnabled(bool enabled
)
623 QThread
*thr
= currentThread();
624 Q_ASSERT_X(thr
!= 0, "QThread::setTerminationEnabled()",
625 "Current thread was not started with QThread.");
628 pthread_setcancelstate(enabled
? PTHREAD_CANCEL_ENABLE
: PTHREAD_CANCEL_DISABLE
, NULL
);
630 pthread_testcancel();
632 QThreadPrivate
*d
= thr
->d_func();
633 QMutexLocker
locker(&d
->mutex
);
634 d
->terminationEnabled
= enabled
;
635 if (enabled
&& d
->terminatePending
) {
636 d
->terminated
= true;
638 // - lockAnyway = false. Don't lock the mutex because it's already locked
640 QThreadPrivate::finish(thr
, false);
641 locker
.unlock(); // don't leave the mutex locked!
647 void QThread::setPriority(Priority priority
)
650 QMutexLocker
locker(&d
->mutex
);
652 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
656 d
->priority
= priority
;
658 // copied from start() with a few modifications:
660 #if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
664 if (pthread_getschedparam(d
->thread_id
, &sched_policy
, ¶m
) != 0) {
665 // failed to get the scheduling policy, don't bother setting
667 qWarning("QThread::setPriority: Cannot get scheduler parameters");
671 int prio_min
= sched_get_priority_min(sched_policy
);
672 int prio_max
= sched_get_priority_max(sched_policy
);
673 if (prio_min
== -1 || prio_max
== -1) {
674 // failed to get the scheduling parameters, don't
675 // bother setting the priority
676 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
682 case InheritPriority
:
683 qWarning("QThread::setPriority: Argument cannot be InheritPriority");
690 case TimeCriticalPriority
:
695 // crudely scale our priority enum values to the prio_min/prio_max
696 prio
= (priority
* (prio_max
- prio_min
) / TimeCriticalPriority
) + prio_min
;
697 prio
= qMax(prio_min
, qMin(prio_max
, prio
));
701 param
.sched_priority
= prio
;
702 pthread_setschedparam(d
->thread_id
, sched_policy
, ¶m
);
706 #endif // QT_NO_THREAD