diff options
Diffstat (limited to 'src/corelib/thread/qthread_unix.cpp')
-rw-r--r-- | src/corelib/thread/qthread_unix.cpp | 213 |
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) { |