summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qthread_unix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/thread/qthread_unix.cpp')
-rw-r--r--src/corelib/thread/qthread_unix.cpp213
1 files changed, 152 insertions, 61 deletions
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 69a11b2b62..1bb8e613e0 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -61,6 +61,10 @@
#include "qdebug.h"
+#ifdef __GLIBCXX__
+#include <cxxabi.h>
+#endif
+
#include <sched.h>
#include <errno.h>
@@ -105,6 +109,10 @@
#define QT_HAS_THREAD_PRIORITY_SCHEDULING
#endif
+#if defined(Q_OS_QNX)
+#include <sys/neutrino.h>
+#endif
+
QT_BEGIN_NAMESPACE
@@ -303,16 +311,14 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data)
#ifndef QT_NO_THREAD
#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
-static void setCurrentThreadName(pthread_t threadId, const char *name)
+static void setCurrentThreadName(const char *name)
{
# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
- Q_UNUSED(threadId);
prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
# elif defined(Q_OS_MAC)
- Q_UNUSED(threadId);
pthread_setname_np(name);
# elif defined(Q_OS_QNX)
- pthread_setname_np(threadId, name);
+ pthread_setname_np(pthread_self(), name);
# endif
}
#endif
@@ -324,49 +330,69 @@ void *QThreadPrivate::start(void *arg)
#endif
pthread_cleanup_push(QThreadPrivate::finish, arg);
- QThread *thr = reinterpret_cast<QThread *>(arg);
- QThreadData *data = QThreadData::get2(thr);
-
+#ifndef QT_NO_EXCEPTIONS
+ try
+#endif
{
- QMutexLocker locker(&thr->d_func()->mutex);
-
- // do we need to reset the thread priority?
- if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
- thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
- }
+ QThread *thr = reinterpret_cast<QThread *>(arg);
+ QThreadData *data = QThreadData::get2(thr);
- data->threadId.store(to_HANDLE(pthread_self()));
- set_thread_data(data);
+ {
+ QMutexLocker locker(&thr->d_func()->mutex);
- data->ref();
- data->quitNow = thr->d_func()->exited;
- }
+ // do we need to reset the thread priority?
+ if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
+ thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
+ }
- if (data->eventDispatcher.load()) // custom event dispatcher set?
- data->eventDispatcher.load()->startingUp();
- else
- createEventDispatcher(data);
+ data->threadId.store(to_HANDLE(pthread_self()));
+ set_thread_data(data);
-#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
- {
- // sets the name of the current thread.
- QString objectName = thr->objectName();
+ data->ref();
+ data->quitNow = thr->d_func()->exited;
+ }
- pthread_t thread_id = from_HANDLE<pthread_t>(data->threadId.load());
- if (Q_LIKELY(objectName.isEmpty()))
- setCurrentThreadName(thread_id, thr->metaObject()->className());
+ if (data->eventDispatcher.load()) // custom event dispatcher set?
+ data->eventDispatcher.load()->startingUp();
else
- setCurrentThreadName(thread_id, objectName.toLocal8Bit());
- }
+ createEventDispatcher(data);
+
+#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
+ {
+ // Sets the name of the current thread. We can only do this
+ // when the thread is starting, as we don't have a cross
+ // platform way of setting the name of an arbitrary thread.
+ if (Q_LIKELY(thr->objectName().isEmpty()))
+ setCurrentThreadName(thr->metaObject()->className());
+ else
+ setCurrentThreadName(thr->objectName().toLocal8Bit());
+ }
#endif
- emit thr->started(QThread::QPrivateSignal());
+ emit thr->started(QThread::QPrivateSignal());
#if !defined(Q_OS_ANDROID)
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- pthread_testcancel();
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
#endif
- thr->run();
+ thr->run();
+ }
+#ifndef QT_NO_EXCEPTIONS
+#ifdef __GLIBCXX__
+ // POSIX thread cancellation under glibc is implemented by throwing an exception
+ // of this type. Do what libstdc++ is doing and handle it specially in order not to
+ // abort the application if user's code calls a cancellation function.
+ catch (const abi::__forced_unwind &) {
+ throw;
+ }
+#endif // __GLIBCXX__
+ catch (...) {
+ qTerminate();
+ }
+#endif // QT_NO_EXCEPTIONS
+ // This pop runs finish() below. It's outside the try/catch (and has its
+ // own try/catch) to prevent finish() to be run in case an exception is
+ // thrown.
pthread_cleanup_pop(1);
return 0;
@@ -374,35 +400,53 @@ void *QThreadPrivate::start(void *arg)
void QThreadPrivate::finish(void *arg)
{
- QThread *thr = reinterpret_cast<QThread *>(arg);
- QThreadPrivate *d = thr->d_func();
+#ifndef QT_NO_EXCEPTIONS
+ try
+#endif
+ {
+ QThread *thr = reinterpret_cast<QThread *>(arg);
+ QThreadPrivate *d = thr->d_func();
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->mutex);
- d->isInFinish = true;
- d->priority = QThread::InheritPriority;
- void *data = &d->data->tls;
- locker.unlock();
- emit thr->finished(QThread::QPrivateSignal());
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QThreadStorageData::finish((void **)data);
- locker.relock();
-
- QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load();
- if (eventDispatcher) {
- d->data->eventDispatcher = 0;
+ d->isInFinish = true;
+ d->priority = QThread::InheritPriority;
+ void *data = &d->data->tls;
locker.unlock();
- eventDispatcher->closingDown();
- delete eventDispatcher;
+ emit thr->finished(QThread::QPrivateSignal());
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QThreadStorageData::finish((void **)data);
locker.relock();
- }
- d->running = false;
- d->finished = true;
- d->interruptionRequested = false;
+ QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load();
+ if (eventDispatcher) {
+ d->data->eventDispatcher = 0;
+ locker.unlock();
+ eventDispatcher->closingDown();
+ delete eventDispatcher;
+ locker.relock();
+ }
- d->isInFinish = false;
- d->thread_done.wakeAll();
+ d->running = false;
+ d->finished = true;
+ d->interruptionRequested = false;
+
+ d->isInFinish = false;
+ d->thread_done.wakeAll();
+ }
+#ifndef QT_NO_EXCEPTIONS
+#ifdef __GLIBCXX__
+ // POSIX thread cancellation under glibc is implemented by throwing an exception
+ // of this type. Do what libstdc++ is doing and handle it specially in order not to
+ // abort the application if user's code calls a cancellation function.
+ catch (const abi::__forced_unwind &) {
+ throw;
+ }
+#endif // __GLIBCXX__
+ catch (...) {
+ qTerminate();
+ }
+#endif // QT_NO_EXCEPTIONS
}
@@ -444,9 +488,6 @@ int QThread::idealThreadCount() Q_DECL_NOTHROW
if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
perror("sysctl");
}
-#elif defined(Q_OS_IRIX)
- // IRIX
- cores = (int)sysconf(_SC_NPROC_ONLN);
#elif defined(Q_OS_INTEGRITY)
#if (__INTEGRITY_MAJOR_VERSION >= 10)
// Integrity V10+ does support multicore CPUs
@@ -512,6 +553,55 @@ void QThread::usleep(unsigned long usecs)
}
#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
+#if defined(Q_OS_QNX)
+static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
+{
+ // On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
+ // than 10 for the "normal" priority but it's difficult to achieve this so we'll
+ // assume that no one has ever created such a system. This makes the mapping from
+ // Qt priorities to QNX priorities lopsided. There's usually more space available
+ // to map into above the "normal" priority than below it. QNX also has a privileged
+ // priority range (for threads that assist the kernel). We'll assume that no Qt
+ // thread needs to use priorities in that range.
+ int priority_norm = 10;
+ // _sched_info::priority_priv isn't documented. You'd think that it's the start of the
+ // privileged priority range but it's actually the end of the unpriviledged range.
+ struct _sched_info info;
+ if (SchedInfo_r(0, *sched_policy, &info) != EOK)
+ return false;
+
+ if (priority == QThread::IdlePriority) {
+ *sched_priority = info.priority_min;
+ return true;
+ }
+
+ if (priority_norm < info.priority_min)
+ priority_norm = info.priority_min;
+ if (priority_norm > info.priority_priv)
+ priority_norm = info.priority_priv;
+
+ int to_min, to_max;
+ int from_min, from_max;
+ int prio;
+ if (priority < QThread::NormalPriority) {
+ to_min = info.priority_min;
+ to_max = priority_norm;
+ from_min = QThread::LowestPriority;
+ from_max = QThread::NormalPriority;
+ } else {
+ to_min = priority_norm;
+ to_max = info.priority_priv;
+ from_min = QThread::NormalPriority;
+ from_max = QThread::TimeCriticalPriority;
+ }
+
+ prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
+ prio = qBound(to_min, prio, to_max);
+
+ *sched_priority = prio;
+ return true;
+}
+#else
// Does some magic and calculate the Unix scheduler priorities
// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
// sched_priority is OUT only
@@ -555,6 +645,7 @@ static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_pr
return true;
}
#endif
+#endif
void QThread::start(Priority priority)
{