Fixing some GCC warnings
[qt-netbsd.git] / src / corelib / thread / qthread_unix.cpp
blob21b5e650905b314f2edaf24596b6207e57ef4544
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
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
14 ** this package.
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.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qthread.h"
44 #include "qplatformdefs.h"
46 #include <private/qcoreapplication_p.h>
47 #if !defined(QT_NO_GLIB)
48 # include "../kernel/qeventdispatcher_glib_p.h"
49 #endif
51 #ifdef Q_OS_SYMBIAN
52 #include <private/qeventdispatcher_symbian_p.h>
53 #else
54 #include <private/qeventdispatcher_unix_p.h>
55 #endif
57 #include "qthreadstorage.h"
59 #include "qthread_p.h"
61 #include "qdebug.h"
63 #include <sched.h>
64 #include <errno.h>
66 #ifdef Q_OS_BSD4
67 #include <sys/sysctl.h>
68 #endif
69 #ifdef Q_OS_VXWORKS
70 # if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
71 # include <vxCpuLib.h>
72 # include <cpuset.h>
73 # define QT_VXWORKS_HAS_CPUSET
74 # endif
75 #endif
77 #if defined(Q_OS_MAC)
78 # ifdef qDebug
79 # define old_qDebug qDebug
80 # undef qDebug
81 # endif
82 # include <CoreServices/CoreServices.h>
84 # ifdef old_qDebug
85 # undef qDebug
86 # define qDebug QT_NO_QDEBUG_MACRO
87 # undef old_qDebug
88 # endif
89 #endif
91 QT_BEGIN_NAMESPACE
93 #ifndef QT_NO_THREAD
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.
104 if (p == (void *)1)
105 return;
106 #endif
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
109 // right value...
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)
117 (void *)1);
118 #else
120 #endif
123 static void create_current_thread_data_key()
125 pthread_key_create(&current_thread_data_key, destroy_current_thread_data);
128 QThreadData *QThreadData::current()
130 pthread_once(&current_thread_data_once, create_current_thread_data_key);
132 QThreadData *data = reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
133 if (!data) {
134 void *a;
135 if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) {
136 QThread *adopted = static_cast<QThread*>(a);
137 Q_ASSERT(adopted);
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();
143 } else {
144 data = new QThreadData;
145 pthread_setspecific(current_thread_data_key, data);
146 QT_TRY {
147 data->thread = new QAdoptedThread(data);
148 } QT_CATCH(...) {
149 pthread_setspecific(current_thread_data_key, 0);
150 data->deref();
151 data = 0;
152 QT_RETHROW;
154 data->deref();
156 if (!QCoreApplicationPrivate::theMainThread)
157 QCoreApplicationPrivate::theMainThread = data->thread;
159 return data;
163 void QAdoptedThread::init()
165 Q_D(QThread);
166 d->thread_id = pthread_self();
167 #ifdef Q_OS_SYMBIAN
168 d->data->symbian_thread_handle = RThread();
169 TThreadId threadId = d->data->symbian_thread_handle.Id();
170 d->data->symbian_thread_handle.Open(threadId);
171 #endif
175 QThreadPrivate
178 #if defined(Q_C_CALLBACKS)
179 extern "C" {
180 #endif
182 typedef void*(*QtThreadCallback)(void*);
184 #if defined(Q_C_CALLBACKS)
186 #endif
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;
197 else
198 #endif
199 #ifdef Q_OS_SYMBIAN
200 data->eventDispatcher = new QEventDispatcherSymbian;
201 #else
202 data->eventDispatcher = new QEventDispatcherUNIX;
203 #endif
204 data->eventDispatcher->startingUp();
207 #ifndef QT_NO_THREAD
209 void *QThreadPrivate::start(void *arg)
211 // Symbian Open C supports neither thread cancellation nor cleanup_push.
212 #ifndef Q_OS_SYMBIAN
213 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
214 pthread_cleanup_push(QThreadPrivate::finish, arg);
215 #endif
217 QThread *thr = reinterpret_cast<QThread *>(arg);
218 QThreadData *data = QThreadData::get2(thr);
220 #ifdef Q_OS_SYMBIAN
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);
228 #endif
230 pthread_once(&current_thread_data_once, create_current_thread_data_key);
231 pthread_setspecific(current_thread_data_key, data);
233 data->ref();
234 data->quitNow = false;
236 // ### TODO: allow the user to create a custom event dispatcher
237 createEventDispatcher(data);
239 emit thr->started();
240 #ifndef Q_OS_SYMBIAN
241 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
242 pthread_testcancel();
243 #endif
244 thr->run();
246 #ifdef Q_OS_SYMBIAN
247 QThreadPrivate::finish(arg);
248 #else
249 pthread_cleanup_pop(1);
250 #endif
252 return 0;
255 #ifdef Q_OS_SYMBIAN
256 void QThreadPrivate::finish(void *arg, bool lockAnyway, bool closeNativeHandle)
257 #else
258 void QThreadPrivate::finish(void *arg)
259 #endif
261 QThread *thr = reinterpret_cast<QThread *>(arg);
262 QThreadPrivate *d = thr->d_func();
263 #ifdef Q_OS_SYMBIAN
264 if (lockAnyway)
265 #endif
266 d->mutex.lock();
268 d->priority = QThread::InheritPriority;
269 d->running = false;
270 d->finished = true;
271 if (d->terminated)
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);
286 d->thread_id = 0;
287 #ifdef Q_OS_SYMBIAN
288 if (closeNativeHandle)
289 d->data->symbian_thread_handle.Close();
290 #endif
291 d->thread_done.wakeAll();
292 #ifdef Q_OS_SYMBIAN
293 if (lockAnyway)
294 #endif
295 d->mutex.unlock();
301 /**************************************************************************
302 ** QThread
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
314 #endif
316 int QThread::idealThreadCount()
318 int cores = -1;
320 #if defined(Q_OS_MAC)
321 // Mac OS X
322 cores = MPProcessorsScheduled();
323 #elif defined(Q_OS_HPUX)
324 // HP-UX
325 struct pst_dynamic psd;
326 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
327 perror("pstat_getdynamic");
328 cores = -1;
329 } else {
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);
335 int mib[2];
336 mib[0] = CTL_HW;
337 mib[1] = HW_NCPU;
338 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
339 perror("sysctl");
340 cores = -1;
342 #elif defined(Q_OS_IRIX)
343 // 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
347 cores = 1;
348 #elif defined(Q_OS_SYMBIAN)
349 // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported
350 cores = 1;
351 #elif defined(Q_OS_VXWORKS)
352 // VxWorks
353 # if defined(QT_VXWORKS_HAS_CPUSET)
354 cpuset_t cpus = vxCpuEnabledGet();
355 cores = 0;
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)) {
360 CPUSET_CLR(cpus, i);
361 cores++;
364 # else
365 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
366 cores = 1;
367 # endif
368 #else
369 // the rest: Linux, Solaris, AIX, Tru64
370 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
371 #endif
373 return cores;
376 void QThread::yieldCurrentThread()
378 sched_yield();
381 /* \internal
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)
387 pthread_mutex_t mtx;
388 pthread_cond_t cnd;
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)
403 struct timeval tv;
404 gettimeofday(&tv, 0);
405 struct timespec ti;
406 ti.tv_sec = tv.tv_sec + secs;
407 ti.tv_nsec = (tv.tv_usec * 1000);
408 thread_sleep(&ti);
411 void QThread::msleep(unsigned long msecs)
413 struct timeval tv;
414 gettimeofday(&tv, 0);
415 struct timespec ti;
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;
420 thread_sleep(&ti);
423 void QThread::usleep(unsigned long usecs)
425 struct timeval tv;
426 gettimeofday(&tv, 0);
427 struct timespec ti;
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;
432 thread_sleep(&ti);
435 void QThread::start(Priority priority)
437 Q_D(QThread);
438 QMutexLocker locker(&d->mutex);
439 if (d->running)
440 return;
442 d->running = true;
443 d->finished = false;
444 d->terminated = false;
446 pthread_attr_t attr;
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
454 switch (priority) {
455 case InheritPriority:
457 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
458 break;
461 default:
463 int sched_policy;
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");
468 break;
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");
477 break;
480 int prio;
481 switch (priority) {
482 case IdlePriority:
483 prio = prio_min;
484 break;
486 case TimeCriticalPriority:
487 prio = prio_max;
488 break;
490 default:
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));
494 break;
497 sched_param sp;
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);
506 break;
509 #endif // _POSIX_THREAD_PRIORITY_SCHEDULING
511 #ifdef Q_OS_SYMBIAN
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.
516 #endif
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);
521 #else
522 int code = ENOSYS; // stack size not supported, automatically fail
523 #endif // _POSIX_THREAD_ATTR_STACKSIZE
525 if (code) {
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...
531 d->running = false;
532 d->finished = false;
533 return;
537 int code =
538 pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
539 if (code == EPERM) {
540 // caller does not have permission to set the scheduling
541 // parameters/policy
542 #ifndef Q_OS_SYMBIAN
543 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
544 #endif
545 code =
546 pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
549 pthread_attr_destroy(&attr);
551 if (code) {
552 qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));
554 d->running = false;
555 d->finished = false;
556 d->thread_id = 0;
557 #ifdef Q_OS_SYMBIAN
558 d->data->symbian_thread_handle.Close();
559 #endif
563 void QThread::terminate()
565 Q_D(QThread);
566 QMutexLocker locker(&d->mutex);
568 if (!d->thread_id)
569 return;
571 #ifndef Q_OS_SYMBIAN
572 int code = pthread_cancel(d->thread_id);
573 if (code) {
574 qWarning("QThread::start: Thread termination error: %s",
575 qPrintable(qt_error_string((code))));
576 } else {
577 d->terminated = true;
579 #else
580 if (!d->running)
581 return;
582 if (!d->terminationEnabled) {
583 d->terminatePending = true;
584 return;
587 d->terminated = true;
588 // "false, false" meaning:
589 // 1. lockAnyway = false. Don't lock the mutex because it's already locked
590 // (see above).
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();
596 #endif
601 bool QThread::wait(unsigned long time)
603 Q_D(QThread);
604 QMutexLocker locker(&d->mutex);
606 if (d->thread_id == pthread_self()) {
607 qWarning("QThread::wait: Thread tried to wait on itself");
608 return false;
611 if (d->finished || !d->running)
612 return true;
614 while (d->running) {
615 if (!d->thread_done.wait(locker.mutex(), time))
616 return false;
618 return true;
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.");
626 #ifndef Q_OS_SYMBIAN
627 Q_UNUSED(thr)
628 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
629 if (enabled)
630 pthread_testcancel();
631 #else
632 QThreadPrivate *d = thr->d_func();
633 QMutexLocker locker(&d->mutex);
634 d->terminationEnabled = enabled;
635 if (enabled && d->terminatePending) {
636 d->terminated = true;
637 // "false" meaning:
638 // - lockAnyway = false. Don't lock the mutex because it's already locked
639 // (see above).
640 QThreadPrivate::finish(thr, false);
641 locker.unlock(); // don't leave the mutex locked!
642 pthread_exit(NULL);
644 #endif
647 void QThread::setPriority(Priority priority)
649 Q_D(QThread);
650 QMutexLocker locker(&d->mutex);
651 if (!d->running) {
652 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
653 return;
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)
661 int sched_policy;
662 sched_param param;
664 if (pthread_getschedparam(d->thread_id, &sched_policy, &param) != 0) {
665 // failed to get the scheduling policy, don't bother setting
666 // the priority
667 qWarning("QThread::setPriority: Cannot get scheduler parameters");
668 return;
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");
677 return;
680 int prio;
681 switch (priority) {
682 case InheritPriority:
683 qWarning("QThread::setPriority: Argument cannot be InheritPriority");
684 return;
686 case IdlePriority:
687 prio = prio_min;
688 break;
690 case TimeCriticalPriority:
691 prio = prio_max;
692 break;
694 default:
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));
698 break;
701 param.sched_priority = prio;
702 pthread_setschedparam(d->thread_id, sched_policy, &param);
703 #endif
706 #endif // QT_NO_THREAD
708 QT_END_NAMESPACE