d458ee947248646e43486edcb426afcc574c4de6
[profile/ivi/qtbase.git] / src / corelib / thread / qthread_unix.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qthread.h"
43
44 #include "qplatformdefs.h"
45
46 #include <private/qcoreapplication_p.h>
47 #if !defined(QT_NO_GLIB)
48 #  include "../kernel/qeventdispatcher_glib_p.h"
49 #endif
50
51 #include <private/qeventdispatcher_unix_p.h>
52
53 #include "qthreadstorage.h"
54
55 #include "qthread_p.h"
56
57 #include "qdebug.h"
58
59 #include <sched.h>
60 #include <errno.h>
61
62 #ifdef Q_OS_BSD4
63 #include <sys/sysctl.h>
64 #endif
65 #ifdef Q_OS_VXWORKS
66 #  if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
67 #    include <vxCpuLib.h>
68 #    include <cpuset.h>
69 #    define QT_VXWORKS_HAS_CPUSET
70 #  endif
71 #endif
72
73 #ifdef Q_OS_HPUX
74 #include <sys/pstat.h>
75 #endif
76
77 #if defined(Q_OS_MAC)
78 # ifdef qDebug
79 #   define old_qDebug qDebug
80 #   undef qDebug
81 # endif
82 #ifndef QT_NO_CORESERVICES
83 # include <CoreServices/CoreServices.h>
84 #endif //QT_NO_CORESERVICES
85
86 # ifdef old_qDebug
87 #   undef qDebug
88 #   define qDebug QT_NO_QDEBUG_MACRO
89 #   undef old_qDebug
90 # endif
91 #endif
92
93 #if defined(Q_OS_LINUX)
94 #include <sys/prctl.h>
95 #endif
96
97 #if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
98 // from linux/sched.h
99 # define SCHED_IDLE    5
100 #endif
101
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
104 #endif
105
106
107 QT_BEGIN_NAMESPACE
108
109 #ifndef QT_NO_THREAD
110
111 enum { ThreadPriorityResetFlag = 0x80000000 };
112
113 #if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL))
114 #define HAVE_TLS
115 #endif
116 #if defined(Q_CC_XLC) || defined (Q_CC_SUN)
117 #define HAVE_TLS
118 #endif
119
120 #ifdef HAVE_TLS
121 static __thread QThreadData *currentThreadData = 0;
122 #endif
123
124 static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
125 static pthread_key_t current_thread_data_key;
126
127 static void destroy_current_thread_data(void *p)
128 {
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.
133     if (p == (void *)1)
134         return;
135 #endif
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
138     // right value...
139     pthread_setspecific(current_thread_data_key, p);
140     QThreadData *data = static_cast<QThreadData *>(p);
141     if (data->isAdopted) {
142         QThread *thread = data->thread;
143         Q_ASSERT(thread);
144         QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
145         Q_ASSERT(!thread_p->finished);
146         thread_p->finish(thread);
147     }
148     data->deref();
149
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)
155                                                  (void *)1);
156 #else
157                                                  0);
158 #endif
159 }
160
161 static void create_current_thread_data_key()
162 {
163     pthread_key_create(&current_thread_data_key, destroy_current_thread_data);
164 }
165
166 static void destroy_current_thread_data_key()
167 {
168     pthread_once(&current_thread_data_once, create_current_thread_data_key);
169     pthread_key_delete(current_thread_data_key);
170 }
171 Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
172
173
174 // Utility functions for getting, setting and clearing thread specific data.
175 static QThreadData *get_thread_data()
176 {
177 #ifdef HAVE_TLS
178     return currentThreadData;
179 #else
180     pthread_once(&current_thread_data_once, create_current_thread_data_key);
181     return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
182 #endif
183 }
184
185 static void set_thread_data(QThreadData *data)
186 {
187 #ifdef HAVE_TLS
188     currentThreadData = data;
189 #endif
190     pthread_once(&current_thread_data_once, create_current_thread_data_key);
191     pthread_setspecific(current_thread_data_key, data);
192 }
193
194 static void clear_thread_data()
195 {
196 #ifdef HAVE_TLS
197     currentThreadData = 0;
198 #endif
199     pthread_setspecific(current_thread_data_key, 0);
200 }
201
202 QThreadData *QThreadData::current()
203 {
204     QThreadData *data = get_thread_data();
205     if (!data) {
206         data = new QThreadData;
207         QT_TRY {
208             set_thread_data(data);
209             data->thread = new QAdoptedThread(data);
210         } QT_CATCH(...) {
211             clear_thread_data();
212             data->deref();
213             data = 0;
214             QT_RETHROW;
215         }
216         data->deref();
217         data->isAdopted = true;
218         data->threadId = (Qt::HANDLE)pthread_self();
219         if (!QCoreApplicationPrivate::theMainThread)
220             QCoreApplicationPrivate::theMainThread = data->thread;
221     }
222     return data;
223 }
224
225
226 void QAdoptedThread::init()
227 {
228     Q_D(QThread);
229     d->thread_id = pthread_self();
230 }
231
232 /*
233    QThreadPrivate
234 */
235
236 #if defined(Q_C_CALLBACKS)
237 extern "C" {
238 #endif
239
240 typedef void*(*QtThreadCallback)(void*);
241
242 #if defined(Q_C_CALLBACKS)
243 }
244 #endif
245
246 #endif // QT_NO_THREAD
247
248 void QThreadPrivate::createEventDispatcher(QThreadData *data)
249 {
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;
255     else
256 #endif
257     data->eventDispatcher = new QEventDispatcherUNIX;
258     data->eventDispatcher->startingUp();
259 }
260
261 #ifndef QT_NO_THREAD
262
263 void *QThreadPrivate::start(void *arg)
264 {
265     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
266     pthread_cleanup_push(QThreadPrivate::finish, arg);
267
268     QThread *thr = reinterpret_cast<QThread *>(arg);
269     QThreadData *data = QThreadData::get2(thr);
270
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));
274     }
275
276     data->threadId = (Qt::HANDLE)pthread_self();
277     set_thread_data(data);
278
279     data->ref();
280     {
281         QMutexLocker locker(&thr->d_func()->mutex);
282         data->quitNow = thr->d_func()->exited;
283     }
284
285     if (data->eventDispatcher) // custom event dispatcher set?
286         data->eventDispatcher->startingUp();
287     else
288         createEventDispatcher(data);
289
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();
293
294     if (objectName.isEmpty())
295         objectName = thr->metaObject()->className();
296
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());
301 #endif
302 #endif
303
304     emit thr->started();
305     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
306     pthread_testcancel();
307     thr->run();
308
309     pthread_cleanup_pop(1);
310
311     return 0;
312 }
313
314 void QThreadPrivate::finish(void *arg)
315 {
316     QThread *thr = reinterpret_cast<QThread *>(arg);
317     QThreadPrivate *d = thr->d_func();
318
319     QMutexLocker locker(&d->mutex);
320
321     d->isInFinish = true;
322     d->priority = QThread::InheritPriority;
323     bool terminated = d->terminated;
324     void *data = &d->data->tls;
325     locker.unlock();
326     if (terminated)
327         emit thr->terminated();
328     emit thr->finished();
329     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
330     QThreadStorageData::finish((void **)data);
331     locker.relock();
332     d->terminated = false;
333
334     QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher;
335     if (eventDispatcher) {
336         d->data->eventDispatcher = 0;
337         locker.unlock();
338         eventDispatcher->closingDown();
339         delete eventDispatcher;
340         locker.relock();
341     }
342
343     d->thread_id = 0;
344     d->running = false;
345     d->finished = true;
346
347     d->isInFinish = false;
348     d->thread_done.wakeAll();
349 }
350
351
352
353
354 /**************************************************************************
355  ** QThread
356  *************************************************************************/
357
358 Qt::HANDLE QThread::currentThreadId()
359 {
360     // requires a C cast here otherwise we run into trouble on AIX
361     return (Qt::HANDLE)pthread_self();
362 }
363
364 #if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
365 // LSB doesn't define _SC_NPROCESSORS_ONLN.
366 #  define _SC_NPROCESSORS_ONLN 84
367 #endif
368
369 int QThread::idealThreadCount()
370 {
371     int cores = -1;
372
373 #if defined(Q_OS_MAC) && !defined(QT_NO_CORESERVICES)
374     // Mac OS X
375     cores = MPProcessorsScheduled();
376 #elif defined(Q_OS_HPUX)
377     // HP-UX
378     struct pst_dynamic psd;
379     if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
380         perror("pstat_getdynamic");
381         cores = -1;
382     } else {
383         cores = (int)psd.psd_proc_cnt;
384     }
385 #elif defined(Q_OS_BSD4)
386     // FreeBSD, OpenBSD, NetBSD, BSD/OS
387     size_t len = sizeof(cores);
388     int mib[2];
389     mib[0] = CTL_HW;
390     mib[1] = HW_NCPU;
391     if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
392         perror("sysctl");
393         cores = -1;
394     }
395 #elif defined(Q_OS_IRIX)
396     // 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
400     cores = 1;
401 #elif defined(Q_OS_VXWORKS)
402     // VxWorks
403 #  if defined(QT_VXWORKS_HAS_CPUSET)
404     cpuset_t cpus = vxCpuEnabledGet();
405     cores = 0;
406
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)) {
410             CPUSET_CLR(cpus, i);
411             cores++;
412         }
413     }
414 #  else
415     // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
416     cores = 1;
417 #  endif
418 #else
419     // the rest: Linux, Solaris, AIX, Tru64
420     cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
421 #endif
422
423     return cores;
424 }
425
426 void QThread::yieldCurrentThread()
427 {
428     sched_yield();
429 }
430
431 /*  \internal
432     helper function to do thread sleeps, since usleep()/nanosleep()
433     aren't reliable enough (in terms of behavior and availability)
434 */
435 static void thread_sleep(struct timespec *ti)
436 {
437     pthread_mutex_t mtx;
438     pthread_cond_t cnd;
439
440     pthread_mutex_init(&mtx, 0);
441     pthread_cond_init(&cnd, 0);
442
443     pthread_mutex_lock(&mtx);
444     (void) pthread_cond_timedwait(&cnd, &mtx, ti);
445     pthread_mutex_unlock(&mtx);
446
447     pthread_cond_destroy(&cnd);
448     pthread_mutex_destroy(&mtx);
449 }
450
451 void QThread::sleep(unsigned long secs)
452 {
453     struct timeval tv;
454     gettimeofday(&tv, 0);
455     struct timespec ti;
456     ti.tv_sec = tv.tv_sec + secs;
457     ti.tv_nsec = (tv.tv_usec * 1000);
458     thread_sleep(&ti);
459 }
460
461 void QThread::msleep(unsigned long msecs)
462 {
463     struct timeval tv;
464     gettimeofday(&tv, 0);
465     struct timespec ti;
466
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;
470     thread_sleep(&ti);
471 }
472
473 void QThread::usleep(unsigned long usecs)
474 {
475     struct timeval tv;
476     gettimeofday(&tv, 0);
477     struct timespec ti;
478
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;
482     thread_sleep(&ti);
483 }
484
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)
490 {
491 #ifdef SCHED_IDLE
492     if (priority == QThread::IdlePriority) {
493         *sched_policy = SCHED_IDLE;
494         *sched_priority = 0;
495         return true;
496     }
497     const int lowestPriority = QThread::LowestPriority;
498 #else
499     const int lowestPriority = QThread::IdlePriority;
500 #endif
501     const int highestPriority = QThread::TimeCriticalPriority;
502
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)
506         return false;
507
508     int prio;
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));
512
513     *sched_priority = prio;
514     return true;
515 }
516 #endif
517
518 void QThread::start(Priority priority)
519 {
520     Q_D(QThread);
521     QMutexLocker locker(&d->mutex);
522
523     if (d->isInFinish)
524         d->thread_done.wait(locker.mutex());
525
526     if (d->running)
527         return;
528
529     d->running = true;
530     d->finished = false;
531     d->terminated = false;
532     d->returnCode = 0;
533     d->exited = false;
534
535     pthread_attr_t attr;
536     pthread_attr_init(&attr);
537     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
538
539     d->priority = priority;
540
541 #if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
542     switch (priority) {
543     case InheritPriority:
544         {
545             pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
546             break;
547         }
548
549     default:
550         {
551             int sched_policy;
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");
556                 break;
557             }
558
559             int prio;
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");
564                 break;
565             }
566
567             sched_param sp;
568             sp.sched_priority = prio;
569
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);
577             }
578             break;
579         }
580     }
581 #endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
582
583
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);
587 #else
588         int code = ENOSYS; // stack size not supported, automatically fail
589 #endif // _POSIX_THREAD_ATTR_STACKSIZE
590
591         if (code) {
592             qWarning("QThread::start: Thread stack size error: %s",
593                      qPrintable(qt_error_string(code)));
594
595             // we failed to set the stacksize, and as the documentation states,
596             // the thread will fail to run...
597             d->running = false;
598             d->finished = false;
599             return;
600         }
601     }
602
603     int code =
604         pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
605     if (code == EPERM) {
606         // caller does not have permission to set the scheduling
607         // parameters/policy
608         pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
609         code =
610             pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
611     }
612
613     pthread_attr_destroy(&attr);
614
615     if (code) {
616         qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));
617
618         d->running = false;
619         d->finished = false;
620         d->thread_id = 0;
621     }
622 }
623
624 void QThread::terminate()
625 {
626     Q_D(QThread);
627     QMutexLocker locker(&d->mutex);
628
629     if (!d->thread_id)
630         return;
631
632     int code = pthread_cancel(d->thread_id);
633     if (code) {
634         qWarning("QThread::start: Thread termination error: %s",
635                  qPrintable(qt_error_string((code))));
636     } else {
637         d->terminated = true;
638     }
639 }
640
641 bool QThread::wait(unsigned long time)
642 {
643     Q_D(QThread);
644     QMutexLocker locker(&d->mutex);
645
646     if (d->thread_id == pthread_self()) {
647         qWarning("QThread::wait: Thread tried to wait on itself");
648         return false;
649     }
650
651     if (d->finished || !d->running)
652         return true;
653
654     while (d->running) {
655         if (!d->thread_done.wait(locker.mutex(), time))
656             return false;
657     }
658     return true;
659 }
660
661 void QThread::setTerminationEnabled(bool enabled)
662 {
663     QThread *thr = currentThread();
664     Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
665                "Current thread was not started with QThread.");
666
667     Q_UNUSED(thr)
668     pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
669     if (enabled)
670         pthread_testcancel();
671 }
672
673 void QThread::setPriority(Priority priority)
674 {
675     Q_D(QThread);
676     QMutexLocker locker(&d->mutex);
677     if (!d->running) {
678         qWarning("QThread::setPriority: Cannot set priority, thread is not running");
679         return;
680     }
681
682     d->priority = priority;
683
684     // copied from start() with a few modifications:
685
686 #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
687     int sched_policy;
688     sched_param param;
689
690     if (pthread_getschedparam(d->thread_id, &sched_policy, &param) != 0) {
691         // failed to get the scheduling policy, don't bother setting
692         // the priority
693         qWarning("QThread::setPriority: Cannot get scheduler parameters");
694         return;
695     }
696
697     int prio;
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");
702         return;
703     }
704
705     param.sched_priority = prio;
706     int status = pthread_setschedparam(d->thread_id, sched_policy, &param);
707
708 # ifdef SCHED_IDLE
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, &param);
713         param.sched_priority = sched_get_priority_min(sched_policy);
714         pthread_setschedparam(d->thread_id, sched_policy, &param);
715     }
716 # else
717     Q_UNUSED(status);
718 # endif // SCHED_IDLE
719 #endif
720 }
721
722 #endif // QT_NO_THREAD
723
724 QT_END_NAMESPACE
725